Advanced Lane Detection & Tracking - Self-Driving Car NanoDegree

Dean Webb - Advanced Lane Detection & Tracking Pipeline

Self-Driving Car Engineer Nanodegee - Project 4

In this project, our goal is to write a software pipeline to identify the lane boundaries in an input video. An example summary of all techniques applied to a test image can be seen below for reference:


alt text


alt text


Project Goals

The goals / steps of this project are the following:

  • Compute the camera calibration matrix and distortion coefficients given a set of chessboard images.
  • Apply a distortion correction to raw images.
  • Use color transforms, gradients, etc., to create a thresholded binary image.
  • Apply a perspective transform to rectify binary image ("birds-eye view").
  • Detect lane pixels and fit to find the lane boundary.
  • Determine the curvature of the lane and vehicle position with respect to center.
  • Warp the detected lane boundaries back onto the original image.
  • Output visual display of the lane boundaries and numerical estimation of lane curvature and vehicle position.

Dependencies

The images for camera calibration are stored in the folder called camera_cal. The images in test_images are for testing your pipeline on single frames. If you want to extract more test images from the videos, you can simply use an image writing method like cv2.imwrite(), i.e., you can read the video in frame by frame as usual, and for frames you want to save for later you can write to an image file.

To help the reviewer examine your work, please save examples of the output from each stage of your pipeline in the folder called ouput_images, and include a description in your writeup for the project of what each image shows. The video called project_video.mp4 is the video your pipeline should work well on.

The challenge_video.mp4 video is an extra (and optional) challenge for you if you want to test your pipeline under somewhat trickier conditions. The harder_challenge.mp4 video is another optional challenge and is brutal!


Rubric Points

Here I will consider the rubric points individually and describe how I addressed each point in my implementation.


Writeup / README

1. Provide a Writeup / README that includes all the rubric points and how you addressed each one. You can submit your writeup as markdown or pdf.

Done! - See below.

Camera Calibration

1. Briefly state how you computed the camera matrix and distortion coefficients. Provide an example of a distortion corrected calibration image.

  • The code for this step is contained in the code cells of the attached IPython notebook. The output is also located in "data/output_images/corners_found11.jpg".

  • I start by preparing "object points", which will be the (x, y, z) coordinates of the chessboard corners in the world. Here I am assuming the chessboard is fixed on the (x, y) plane at z=0, such that the object points are the same for each calibration image.

  • Thus, objp is just a replicated array of coordinates, and objpoints will be appended with a copy of it every time I successfully detect all chessboard corners in a test image. imgpoints will be appended with the (x, y) pixel position of each of the corners in the image plane with each successful chessboard detection.

  • I then used the output objpoints and imgpoints to compute the camera calibration and distortion coefficients using the cv2.calibrateCamera() function. An example of this process can be seen below:


Original Undistorted

For added visual effect above, I added the color markings that were computed using cv2.findChessboardCorners() - (See e.g., code cells 3-4 of advanced-lane-lines-setup.ipynb).


Lane-Finding Pipeline (single images)

1. Provide an example of a distortion-corrected test image.

I also applied this distortion correction to the test image using the cv2.undistort() function and obtained this result:


Test Img Undistorted Img

2. Describe how (and identify where in your code) you used color transforms, gradients or other methods to create a thresholded binary image. Provide an example of a binary image result.

I used a combination of color and gradient thresholds to generate the binary image, as shown in the code snippet below for convenience. This snippet for applying the thresholds can also be seen in code cell 12 of advanced-lane-lines-setup.ipynb).


alt text


It took quite a long time to figure out the optimal configuration of thresholds to apply. In many ways the values are stil lnot perfect! However, the smoothing factor applied during video generation helps keep track of the lines once they are found. Conveniently, below are some examples of my generated output for my custom thresholding technique. I found the v_channel, s_channel, and l_channel color binary channels carried a lot of information with them, which helped in detection of the lines in the output throsholded image. Please note: The color stacked binary image is not included in the output, it is added here for illustration purposes.

Undistorted Img Color Binaries Thresholded Img

3. Describe how (and identify where in your code) you performed a perspective transform and provide an example of a transformed image.

The code for my perspective transform includes a function called apply_perspective_transform(), which appears in the code snippet (which has been included below for the reviewer's convenience. This snippet for applying the perspective transform can also be seen in code cell 13 of advanced-lane-lines-setup.ipynb). The apply_perspective_transform() function takes as inputs an image (img). I also included (as an optional parameter) the M_pickle file, which contains the Transformation Matrix (M), as well as the Inverse Transformation Matrix (Minv), both of which are calculated by warpPerspective() from the OpenCV library. For our purposes, we will use this function with the flag cv2.INTER_LINEAR, which is described by the source as a a bilinear interpolation..


alt text


By including the M_pickle file, the function can optionally bypass the recalculation of the source (src) and destination (dst) points if the file exists. As hinted by the name, we use this function to warp the image in such a way that it appearsto change its orientation. For example, we will use the image warping to map a bird's eye view of the lane lines so that it would be easier to detect the parallel nature of the lanes. But forst, we must capture the perspective in it's image space. I used a trapezoidal shape with the intention on transforming the points into a rectangular one. Instead of fully hardcoding the source and destination points, the function attempts to partially generate these source (src) and destination (dst) points based on the image size variables, and the desired trapezoidal destination region. As shown above, these weighted variables shape the trapezoid by plotting its:

  • Bottom Trapezoidal Width (bottom_width)
  • Middle Trapezoidal Width (mid_width)
  • Percent of the Trapezoidal Height (height_pct)
  • Percent to Trim from top to bottom - to remove the car's hood (bottom_trim)

By tuning these parameters, I verified that my perspective transform was working as expected by drawing the src and dst points onto a test image and its warped counterpart to verify that the lines appear parallel in the warped image. Below are examples of my generated output for this perspective transform technique.

Undistorted Img Persp. Trans Img Inverted Masked

4. Describe how (and identify where in your code) you identified lane-line pixels and fit their positions with a polynomial?

In order to identify the laneline pixels. I used a convolutional technique, which can be found in the tracker() class in the advanced-lane-lines-setup.ipynb file. The tracker class advantageously has a function called find_window_centroids which does a lot of the heavy lifting involved with detecting windows. I found this technique to work much better than my original plan to use a Histogram of pixel in the vertical axis.Once the windows were detected by the tracker class. I did various array manipulations and concatenations to select the left-lane points and the right-lane points. Next, I further applied some matrix manipulations and region masking in order to fit the detected lane lines within a 2nd order polynomial. I note that the "lines" pixels of the second order polynomial are determined by plotting the windows gathered by the windows centroids from the tracker class. More specifically, I used the center of the windows and plotted them in green in order to find the line. Because the windows were detected as a convolution, the was much less noise than the histogram technique. For reference, below is a visualization of the resulting processed image, with the lines detected:


alt text


The code for the above shown image can be found in the pipeline() function, which appears in a code cell with the header "Lane Tracking Pipeline." This function accepts a list of images and applies all computer vision techniques on the image to produce an overview (the same overview plotted at the beginning of this report.) In addition to the pipeline() function, I similarly created a process_image() function to be applied on a single image frame. The key difference between the two methods is that the process_image() function bypasses all of the visualization plots, debugger logging and image saving that exists in the pipeline() function.

5. Describe how (and identify where in your code) you calculated the radius of curvature of the lane and the position of the vehicle with respect to center.

Following this handy radius of curvature tutorial, I was able to apply the technique on the resulting image. Once these values where calculated I then plotted the values directly onto the image for verification that the lanes are in fact curved. As shown in the code snippet below for convenience, this snippet for calculating the radius of curvature is as follows:


alt text


Note: This snippet is fully shown in various code cells of advanced-lane-lines-setup.ipynb. Particularly, the radius of curvature is calculated in the pipeline() and process_image() functions.

6. Provide an example image of your result plotted back down onto the road such that the lane area is identified clearly.

As noted above, I implemented this step in the pipeline() and process_image() functions. Here is an example of my result on a test image:


alt text


Pipeline (video)

Here's a link to my video result


Discussions / Learnings

1. Briefly discuss any problems / issues you faced in your implementation of this project. Where will your pipeline likely fail? What could you do to make it more robust?

Here I'll talk about the approach I took, what techniques I used, what worked and why, where the pipeline might fail and how I might improve it if I were going to pursue this project further.

The biggest problems I faced with implementation had to do with the mpimg().imread versus cv2.imread() functions for reading in images. Not only do these libraries differ in their orientation of the matrix (BGR) for Open CV functions, versus (RGB) for impimg.imread() functions. This took quite some time getting used to and I still have occasional hiccups with that implementation.

Another issue was that originally I used a Histogram to try and detect the polynomial fitted lines, but I found the method to not be very accurate. As such, in order to order to identify the lane pixels, I implemented the convolutional technique described above. However, I still found the Histogram function to be quite useful for debugging and tuning my parameters for region masking. As an example of how I used this, I include below an analysis function I utilized to tweak my parameters:


alt text


Since I implemented. By far the best strategy I used was the pipeline() function, as it goes through and applies all of the required transformations and then saves the images into a directory. This strategy allowed my to slowly develop and to "fail fast." That is, I was able to recognize bugs in the code or mistakes in my logic by simply looking at the output image each step. I initially tried to implement the vehicle detection tracking project without this intermediary process of plotting and saving example images. I believe this will help me further limit the false positives that have been plaguing my results (and delaying my submission).

I am satisfied with my lane line detection accuracy but I definitely believe I could spend a great deal more time on the project perfecting that. I would like to investigate some techniques that might allow me to plot lanes for very sharp turns I quickly realized after testing with the harder_challenge.mp4 video that there are many improvements to be made to the algorithm I used. I noticed many scenarios that easily broke my lane detection algorithms, such as the road changing color. To fix this, I would process a subclip of the video, and rocess and print each frame to see what the algorithm was doing. In one such instance, noticed the algorithm picking up the right lane car's wheel whenever the dashed-right lane line was missing. This allowed me to appropriately remove the false positives and complete detection on pretty much all of the frames. I believe a further investigation is in order to look into optimizing may lane-detection algorithm. I am pretty motivated to complete this sooner rather than later, since I plan to participate in the Didi and Udacity Self Driving Car Challenge!

One more optimization I think would be great is if I could design the code to obviously run faster. I was more concerned with accuracy than speed for this project. Now that things are fairly accurate, I would investigate how to get it to process faster than the single-image-per-second threshold.

Still further, I think this detection would be a prime candidate to apply deep learning techniques. That is to say, to train a convolutional neural network to take in the input as an image and predict a list of window centroids that are centered on the left and right lanes. In fact, I think that if I implement such an algorithm I would be able to satisfy all 3 of my optimization ideas.

Import Dependencies

In [1]:
# Camera Calibration
import numpy as np
import cv2
import glob
import pickle
import os

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
%matplotlib inline

Constants

In [2]:
WORKING_DIRECTORY = 'data/'
IMAGE_EXTENSION = '.jpg'
OUTPUT_DIRECTORY = 'output_images/'
DATACACHE_DIRECTORY = "datacache/"

# Calibration Constants #
CALIBRATION_DIRECTORY = 'camera_cal/'
CALIBRATION_PREFIX = 'corners_found'
calibration_path = "{}{}{}".format(WORKING_DIRECTORY, CALIBRATION_DIRECTORY, '*'+IMAGE_EXTENSION)
dist_pickle_file = os.path.join(WORKING_DIRECTORY, DATACACHE_DIRECTORY, "calibration_pickle.p")
CHESSBOARD_SIZE = (9,6)

# Threshold Constants #
TEST_IMAGE_DIRECTORY = 'test_images/'
THRESHOLDING_PREFIX = 'thresholded_'
COLOR_STACKED_PREFIX = 'color_stacked_'
UNDISTORTED_PREFIX = 'undistorted'
TEST_IMAGES_PREFIX = 'test'
test_images_path = "{}{}{}".format(WORKING_DIRECTORY, TEST_IMAGE_DIRECTORY, TEST_IMAGES_PREFIX+'*'+IMAGE_EXTENSION)

# Perspective Transform Constants #
WARPED_PREFIX = 'warped'
M_pickle_file = os.path.join(WORKING_DIRECTORY, DATACACHE_DIRECTORY, "M_Minv_pickle.p")

# Lane Tracking Constants #
LINES_DRAWN_PREFIX = 'green_lines'
TRACKED_PREFIX = 'tracked'

Camera Calibration

In [3]:
# Calibrate the camera using a 9x6 checkerboard
objp = np.zeros((CHESSBOARD_SIZE[1]*CHESSBOARD_SIZE[0], 3), np.float32)
objp[:,:2] = np.mgrid[0:CHESSBOARD_SIZE[0], 0:CHESSBOARD_SIZE[1]].T.reshape(-1, 2)

# Arrays to store object points and image points from all the images
objpoints = [] # 3-Dim points in real-world space
imgpoints = [] # 2-Dim points in virtual image plane

# Load Calibration Images 
calibration_images = glob.glob(calibration_path, recursive=True)

# Walk through images and search for checkerboard corners
for idx, fname in enumerate(calibration_images):
    img = mpimg.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    
    # Find the checkerboard corners
    ret, corners = cv2.findChessboardCorners(gray, CHESSBOARD_SIZE, None)
    
    # If found, add object points, image points
    if ret == True:
        print('Calibrating image:', fname)
        imgpoints.append(corners)
        objpoints.append(objp)
        
        # Draw and display found corners
        cv2.drawChessboardCorners(img, CHESSBOARD_SIZE, corners, ret)
        output_img_path = "{}{}{}{}{}".format(WORKING_DIRECTORY, OUTPUT_DIRECTORY, CALIBRATION_PREFIX
                                              ,str(idx), IMAGE_EXTENSION)
        print('Saving Calibrated image:', output_img_path)
        os.makedirs(os.path.join(WORKING_DIRECTORY, OUTPUT_DIRECTORY), exist_ok=True)
        cv2.imwrite(output_img_path, img)
Calibrating image: data/camera_cal/calibration10.jpg
Saving Calibrated image: data/output_images/corners_found1.jpg
Calibrating image: data/camera_cal/calibration11.jpg
Saving Calibrated image: data/output_images/corners_found2.jpg
Calibrating image: data/camera_cal/calibration12.jpg
Saving Calibrated image: data/output_images/corners_found3.jpg
Calibrating image: data/camera_cal/calibration13.jpg
Saving Calibrated image: data/output_images/corners_found4.jpg
Calibrating image: data/camera_cal/calibration14.jpg
Saving Calibrated image: data/output_images/corners_found5.jpg
Calibrating image: data/camera_cal/calibration15.jpg
Saving Calibrated image: data/output_images/corners_found6.jpg
Calibrating image: data/camera_cal/calibration16.jpg
Saving Calibrated image: data/output_images/corners_found7.jpg
Calibrating image: data/camera_cal/calibration17.jpg
Saving Calibrated image: data/output_images/corners_found8.jpg
Calibrating image: data/camera_cal/calibration18.jpg
Saving Calibrated image: data/output_images/corners_found9.jpg
Calibrating image: data/camera_cal/calibration19.jpg
Saving Calibrated image: data/output_images/corners_found10.jpg
Calibrating image: data/camera_cal/calibration2.jpg
Saving Calibrated image: data/output_images/corners_found11.jpg
Calibrating image: data/camera_cal/calibration20.jpg
Saving Calibrated image: data/output_images/corners_found12.jpg
Calibrating image: data/camera_cal/calibration3.jpg
Saving Calibrated image: data/output_images/corners_found13.jpg
Calibrating image: data/camera_cal/calibration6.jpg
Saving Calibrated image: data/output_images/corners_found16.jpg
Calibrating image: data/camera_cal/calibration7.jpg
Saving Calibrated image: data/output_images/corners_found17.jpg
Calibrating image: data/camera_cal/calibration8.jpg
Saving Calibrated image: data/output_images/corners_found18.jpg
Calibrating image: data/camera_cal/calibration9.jpg
Saving Calibrated image: data/output_images/corners_found19.jpg

Save Calibration Variables to Pickle File

In [4]:
# Load image for reference
if os.path.exists(dist_pickle_file):
    dist_pickle = pickle.load( open(dist_pickle_file, "rb"))
else:
    dist_pickle = {}

img = cv2.imread(calibration_images[0])
img_size = (img.shape[1], img.shape[0])

# Perform calibration given object points and image points
if ("mtx" in dist_pickle and "dist" in dist_pickle):
    mtx = dist_pickle["mtx"]
    dist = dist_pickle["dist"]
else:
    ret, mtx, dist, _, _ = cv2.calibrateCamera(objpoints, imgpoints, img_size, None, None)

# Save camera calibration result data
dist_pickle = {}
dist_pickle["mtx"] = mtx
dist_pickle["dist"] = dist

os.makedirs(os.path.join(WORKING_DIRECTORY, DATACACHE_DIRECTORY), exist_ok=True)
pickle.dump(dist_pickle, open(dist_pickle_file, "wb"))

Undistort Test Images

In [5]:
import pickle

# Read in the saved objpoints and imgpoints
dist_pickle = pickle.load( open(dist_pickle_file, "rb"))
mtx = dist_pickle["mtx"]
dist = dist_pickle["dist"]

Sobel and Gradient Thresholding Functions

In [6]:
def abs_sobel_thresh(sobel_img, sobel_kernel=9, thresh=(20, 100)):
    # Take the absolute value on Sobel function
    abs_sobel = np.absolute(sobel_img)
    # Rescale back to 8 bit integer
    scaled_sobel = np.uint8(255*abs_sobel/np.max(abs_sobel))
    # Create a copy and apply the threshold
    binary_output = np.zeros_like(scaled_sobel)
    binary_output[(scaled_sobel >= thresh[0]) & (scaled_sobel <= thresh[1])] = 1
    return binary_output
In [7]:
def mag_threshold(sobelx, sobely, sobel_kernel=9, mag_thresh=(0, 255)):
    # Calculate the gradient magnitude
    gradmag = np.sqrt(sobelx**2 + sobely**2)
    # Rescale to 8 bit
    scale_factor = np.max(gradmag)/255 
    gradmag = (gradmag/scale_factor).astype(np.uint8) 
    # Create a binary image of ones where threshold is met, zeros otherwise
    mag_binary = np.zeros_like(gradmag)
    mag_binary[(gradmag >= mag_thresh[0]) & (gradmag <= mag_thresh[1])] = 1

    # Return the binary image
    return mag_binary
In [8]:
def dir_threshold(sobelx, sobely, sobel_kernel=3, thresh=(0, np.pi/2)):
    # Take the absolute value of the gradient direction, 
    # apply a threshold, and create a binary image result
    absgraddir = np.arctan2(np.absolute(sobely), np.absolute(sobelx))
    dir_binary =  np.zeros_like(absgraddir)
    dir_binary[(absgraddir >= thresh[0]) & (absgraddir <= thresh[1])] = 1
    return dir_binary

Window Masking Function - For Lane Tracking

In [9]:
def window_mask(width, height, img_ref, center, level):
    output = np.zeros_like(img_ref)
    
    # Fill in template with ones
    output[int(img_ref.shape[0]-(level+1)*height):
           int(img_ref.shape[0]-level*height),
           max(0, int(center-width)):min(int(center+width), img_ref.shape[1])] = 1
    
    return output
In [10]:
# Define a function to scale .PNG and JPEG Files both to 0 to 1 
def normalize_pixels(img):
    max_pixel_value = np.max(img)
    if max_pixel_value > 1.0:
        img = np.copy(np.multiply(img, 1.0 / 255.0)).astype(np.float64) 
    return img

# Define a function to scale .PNG and JPEG Files both to 0 to 1 
def denormalize_pixels(img):
    max_pixel_value = np.max(img)
    if max_pixel_value <= 1.0:
        img = np.copy(np.multiply(img, 255.0)).astype(np.float64) 
    return img
In [11]:
def apply_thresholds(img, kernel_size=13, l_thresh=(115, 130), v_thresh=(190, 255), s_thresh=(150, 255), sx_thresh=(22, 100), sy_thresh=(25, 40)):   
    img = np.copy(img)

    # Convert to HLS color space and separate the S and L channel
    hls = cv2.cvtColor(img, cv2.COLOR_RGB2HLS).astype(np.float)
    l_channel = hls[:,:,1]
    s_channel = hls[:,:,2]
    # Convert to HSV color space and separate the V channel
    hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV).astype(np.float)
    v_channel = hsv[:,:,2]

    # Threshold l-channel
    l_binary = np.zeros_like(l_channel)
    l_binary[(l_channel >= l_thresh[0]) & (l_channel <= l_thresh[1])] = 1
    
    # Threshold s-channel
    s_binary = np.zeros_like(s_channel)
    s_binary[(s_channel >= s_thresh[0]) & (s_channel <= s_thresh[1])] = 1
    
    # Threshold v-channel
    v_binary = np.zeros_like(v_channel)
    v_binary[(v_channel >= v_thresh[0]) & (v_channel <= v_thresh[1])] = 1
    
    # Sobel Operator
    sobelx = cv2.Sobel(v_channel, cv2.CV_64F, 1, 0, ksize=kernel_size)
    sobely = cv2.Sobel(v_channel, cv2.CV_64F, 0, 1, ksize=kernel_size)

    # Calculate Abs value and Threshold pixels after Sobel Operator
    gradx_binary = abs_sobel_thresh(sobelx, sobel_kernel=15, thresh=sx_thresh)
    grady_binary = abs_sobel_thresh(sobely, sobel_kernel=15, thresh=sy_thresh)
    
    # Threshold magnitude and direction gradients
    mag_binary = mag_threshold(sobelx, sobely, sobel_kernel=kernel_size, mag_thresh=(30, 100))
    dir_binary = dir_threshold(sobelx, sobely, sobel_kernel=15, thresh=(0.7, 1.3))

    # Stack 2 channels for color_binary
    color_binary = np.dstack(( l_binary, s_binary, v_binary))

    combined = np.zeros_like(s_channel)
    combined[((v_binary == 1) & (s_binary == 1)) |
            ((gradx_binary == 1) & (v_binary == 1)) |
            ((mag_binary == 1) & (dir_binary == 1)) |
            ((l_binary == 1) & (mag_binary == 1) & (v_binary == 1)) |
            ((mag_binary == 1) & (v_binary == 1))] = 1        
    return color_binary, combined

Lane Tracker Class

In [12]:
import numpy as np
import cv2
class tracker():
    def __init__(self, win_width, win_height, margin, y_m = 1, x_m = 1, smoothing_factor = 20):
        # List that stores all the past (left, right) center set values used for smoothing the output
        # Average over the center to try to smooth out the result
        self.recent_centers = []
        
        # Window pixel width of center values, used to count pixels inside center windows to determine curve values
        self.window_width = win_width
        
        # Window pixel height of center values, used to count pixels inside center windows to determine curve values
        # Note: Breaks the image into vertical levels
        self.window_height = win_height
        
        # The pixel distance in both directions to slide left_window + right_window template for searching
        self.margin = margin # "Padding" how much the window's allowed to slide around

        # Meters per pixel in vertical dimension
        self.ym_per_pixel = y_m 
        
        # Meters per pixel in horizontal dimension
        self.xm_per_pixel = x_m
        
        self.smooth_factor = smoothing_factor
            
    # Main tracking function below - Used to find and store lane segment positions
    # Note: Uses 'Window Sliding' technique - Find centroid of pixels using 1-Dim convolution in vertical axis
    def find_window_centroids(self, warped):
        window_width = self.window_width
        window_height = self.window_height
        margin = self.margin
        
        window_centroids = [] # Store the (left, right) window centroid positions per level - 9 slices
        window = np.ones(window_width) # Create our convolutional window template that we will use for convolutions
        
        # 1) First Find the starting positions for the left and right lane by using np.sum
        # to get the vertical image slice with the window template

        # Histogram Calculation - Sum quarter bottom of image to get slice, could use a different ratio
        l_sum = np.sum(warped[(3*warped.shape[0]//4):,:(warped.shape[1]//2)], axis=0)
        l_center = np.argmax(np.convolve(window,l_sum))-window_width/2
        r_sum = np.sum(warped[(3*warped.shape[0]//4):, (warped.shape[1]//2):], axis=0)
        r_center = np.argmax(np.convolve(window,r_sum))-window_width/2+(warped.shape[1]//2)
        
        # Add what we found for the first layer
        window_centroids.append((l_center, r_center))
        
        # Append each layer looking for max pixel locations
        for level in range(1, (int)(warped.shape[0]/window_height)):
            # Restart algorithm from position 1 - Convolve the window into the vertical slice of the image
            
            # For Single channel image
            image_layer = np.sum(warped[int(warped.shape[0]-(level+1)*window_height):
                                        int(warped.shape[0]-level*window_height),:], axis=0)
            conv_signal = np.convolve(window, image_layer)
            # Find the best left centroid by using past left center as a reference
            # Use window_width/2 as offset because the convolution signal
            # eference is at right side of window, not center of window
            offset = window_width//2
            l_min_index = int(max(l_center+offset-margin,0))
            l_max_index = int(min(l_center+offset+margin,warped.shape[1]))
            l_center = np.argmax(conv_signal[l_min_index:l_max_index])+l_min_index-offset

            # Find the best right centroid by using past right center as a reference
            r_min_index = int(max(r_center+offset-margin,0))
            r_max_index = int(min(r_center+offset+margin, warped.shape[1]))
            r_center = np.argmax(conv_signal[r_min_index:r_max_index])+r_min_index-offset
            
            # Add what we found for that layer
            window_centroids.append((l_center, r_center))

        self.recent_centers.append(window_centroids)
        # return averaged values of the line centers, helps to keep the markers from jumping aroud
        return np.average(self.recent_centers[-self.smooth_factor:], axis = 0)

Perform Perspective Transform

In [13]:
def apply_perspective_transform(image, filepath=None, M_pickle={}):
    img = np.copy(image)
    img_size = (img.shape[1], img.shape[0])
    bottom_width = .58 # Percent of bottom Trapezoidal Height Previous - Prev .74
    mid_width = .10 # Percent of middle Trapezoidal Height - Prev .10
    height_pct = .64 # Percent of Trapezoidal Height
    bottom_trim = .935 # Percent from top to bottom to avoid car's hood
      
    if filepath:
        head, filename = os.path.split(filepath)
        # Set M and Minv variables to load from Datacache
        M_str = "M_" + filename
        Minv_str = "Minv_" + filename
    else:
        M_str = "M_"+str(image)
        Minv_str = "Minv_"+str(image)
        
    if (M_str in M_pickle and Minv_str in M_pickle):
        M = M_pickle[M_str]
        Minv = M_pickle[Minv_str]
        warped = cv2.warpPerspective(img, M, img_size, flags=cv2.INTER_LINEAR)
    else: # Reload 
        ## Calculate Source Points ##
        src_pt_1 = [img.shape[1]*(.5-mid_width/2), img.shape[0]*height_pct]
        src_pt_2 = [img.shape[1]*(.5+mid_width/2),img.shape[0]*height_pct]
        src_pt_3 = [img.shape[1]*(.5+bottom_width/2),img.shape[0]*(bottom_trim/2+.5)]
        src_pt_4 = [img.shape[1]*(.5-bottom_width/2),img.shape[0]*(bottom_trim/2+.5)]
        src = np.float32([src_pt_1, src_pt_2, src_pt_3, src_pt_4])

        ## Calculate Destination Points ##
        offset = img_size[0]*.23
        dst_pt_1 = [offset, 0]
        dst_pt_2 = [img_size[0]-offset, 0]
        dst_pt_3 = [img_size[0]-offset, img_size[1]]
        dst_pt_4 = [offset, img_size[1]]
        dst = np.float32([dst_pt_1, dst_pt_2, dst_pt_3, dst_pt_4])

        M = cv2.getPerspectiveTransform(src, dst)  
        Minv = cv2.getPerspectiveTransform(dst, src)            
        warped = cv2.warpPerspective(img, M, img_size, flags=cv2.INTER_LINEAR)
        warped = denormalize_pixels(warped)

        # Overwrite Datacache
        M_pickle[M_str] = M
        M_pickle[Minv_str] = Minv
    # Return image 
    return M, Minv, warped

Radius of Curvature Calculation

To determine the Radius of curvature, it is advantageous to (1) select 3 points within the given lane lines, (2) calculate the respective slopes between them, (3) Then use the combination of the slopes and the points to find the circle that intersects all 3 points. This will give us the exact calculation of the radius, as opposed to an approximation. Note: We must remember to (a) take the negative of the slope (since y_positive is oriented downward). We must also be aware of (b) indeterminant values (0 denominator). (c) If we get a slope of infinity, -infinity, or zero or of the like, we should shift our calculation "upward" That is, towards the horizon and try the calculation again.

In [14]:
def calculate_radius_of_curvature(lane_points):
    # Select points
    low, high = 0, len(lane_points)-1
    mid = len(lane_points)//2+1
    
    #Calculate good equi-distant points, where the midpoint is at the center point of the detected curve
    A = lane_points[low]
    B = lane_points[mid]
    C = lane_points[high]
    
    # Calculate slopes        
    x, y = 0, 1
    
    # If slope is verticle, divide lane lines in half and try again.. until you find a slope
    if (B[x] - A[x]) != 0:
        m1 = -np.float64((B[y] - A[y])/(B[x] - A[x]))
    else:
        m1 = 1e8
        
    if (C[x] - B[x]) != 0:
        m2 = -np.float64((C[y] - B[y])/(C[x] - B[x]))
    else:
        m2 = 1e8
        
    # Calculate the Center x Point 
    X_c = (m1*m2*(A[y]-C[y])+m2*(A[x]+B[x])-m1*(B[x]+ C[x]))/2*(m2-m1)
    
    # Calculate the Center y Point (calculate the first perpindicular bysector)
    Y_c = -0.5*(X_c - (A[x]+B[x])/2.) + (A[y]+B[y])/2.
    
    # Calculate the Radius of Curvature
    rad_curv = np.sqrt((B[x] - A[x])**2 + (B[y] - A[y])**2)
    
    # Return the radius
    return rad_curv

Lane Tracking Pipeline

In [28]:
# Load Test Images
test_images_path = "test_images/process/*.jpg"
test_images = glob.glob(test_images_path, recursive=True)
TRACKER = None

def pipeline(test_images):
    # Load Picklefile
    M_pickle_file = os.path.join(WORKING_DIRECTORY, DATACACHE_DIRECTORY, "M_Minv_pickle.p")
    if os.path.exists(M_pickle_file):
        M_pickle = pickle.load( open(M_pickle_file, "rb"))
    else:
        M_pickle = {}

    # Walk through test images
    for idx, filepath in enumerate(test_images):
        img = mpimg.imread(filepath)
        
        head, filename = os.path.split(filepath)
        # Set M and Minv variables to load from Datacache
        M_str = "M_" + filename
        Minv_str = "Minv_" + filename

        # Undistort the image
        img = cv2.undistort(img, mtx, dist, None, mtx)
        color_binary, preprocessed_img = apply_thresholds(img)
        
        # Perspective Transform of Image       
        M, Minv, warped = apply_perspective_transform(preprocessed_img, filepath,  {})
            
        # Instantiate Tracker() class for lane tracking
        window_width = warped.shape[1]//20
        window_height = warped.shape[0]//12
        real_to_pix_x = 3.7/650
        real_to_pix_y = 30./720
        
        if TRACKER is None:
            curve_centers = tracker(win_width=window_width, win_height=window_height, margin = 25,
                                y_m = real_to_pix_y, x_m = real_to_pix_x, smoothing_factor = 30)
        else:
            curve_centers = TRACKER
        
        # Use tracking function to find centroids for drawing lane lines
        window_centroids = curve_centers.find_window_centroids(warped)
        
        # Points used to draw all the left and right windows
        l_points = np.zeros_like(warped)
        r_points = np.zeros_like(warped)
        
        # Points used to find the left and right lanes
        right_x = []
        left_x = []
        
        # Go through even levels and draw the windows
        for level in range(0,len(window_centroids)):
            # Utilize window_mask function above to draw window areas
            l_mask = window_mask(window_width, window_height, warped, window_centroids[level][0], level)
            r_mask = window_mask(window_width, window_height, warped, window_centroids[level][1], level)
            
            # Add center value found in frame to the list of lane points per left, right
            left_x.append(window_centroids[level][0])
            right_x.append(window_centroids[level][1])
            
            # Add graphic points from window mask here to total pixels found
            l_points[(l_points == 255) | ((l_mask == 1.))] = 255
            r_points[(r_points == 255) | ((r_mask == 1.))] = 255
        
        ## Draw the results ##
        # Add both left and right pixels together
        template = np.array(r_points+l_points, np.uint8)
        
        # Create a zero color channel
        zero_channel = np.zeros_like(template)
        
        # Make window pixels green
        template = np.array(cv2.merge((zero_channel, template, zero_channel)), np.uint8)
        warped = denormalize_pixels(warped)
        
        # Making the original road pixels 3 color channels
        channeled_warped = np.array(cv2.merge((warped, warped, warped)), np.uint8)        
        
        # Overlay the original road image with window results
        result = cv2.addWeighted(channeled_warped, 1, template, 0.5, 0.)
        
    
        # Fit the lane boundaries to the left, right, and center positions
        yvals = range(0, warped.shape[0])
        res_yvals = np.arange(warped.shape[0]-(window_height/2),0,-window_height)
        
        left_fit = np.polyfit(res_yvals, left_x, 2)
        # Degree 2 polynomial
        left_fitx = left_fit[0]*yvals*yvals + left_fit[1]*yvals + left_fit[2]
        left_fitx = np.array(left_fitx, np.int32)
        
        right_fit = np.polyfit(res_yvals, right_x, 2)
        # Degree 2 polynomial
        right_fitx = right_fit[0]*yvals*yvals + right_fit[1]*yvals + right_fit[2]
        right_fitx = np.array(right_fitx, np.int32)
        
        # Restructure/Encapsulate array values (to make it pretty)
        left_lane = np.array(list(zip(np.concatenate((left_fitx-window_width/2, left_fitx[::-1]+window_width/2), axis=0),
                                     np.concatenate((yvals, yvals[::-1]), axis=0))), np.int32)
        right_lane = np.array(list(zip(np.concatenate((right_fitx-window_width/2, right_fitx[::-1]+window_width/2), axis=0),
                                      np.concatenate((yvals, yvals[::-1]), axis=0))), np.int32)
        middle_lane = np.array(list(zip(np.concatenate((right_fitx-window_width/2, right_fitx[::-1]+window_width/2), axis=0),
                                       np.concatenate((yvals, yvals[::-1]), axis=0))), np.int32)
          
        # Recast x and y points
        pts_left = np.array([np.transpose(np.vstack([left_fitx, yvals]))])
        pts_right = np.array([np.flipud(np.transpose(np.vstack([right_fitx, yvals])))])
        pts = np.hstack((pts_left, pts_right))

        road = np.zeros_like(img)
        road_background = np.zeros_like(img)
        
        # Draw the lane onto the warped blank image
        cv2.fillPoly(road, np.int_([pts]), (0,200, 200))
        cv2.fillPoly(road, [left_lane], color=[255,0, 50])
        cv2.fillPoly(road, [right_lane], color=[50, 0, 255])
        
        # Use these to make negate pixels during cv2.addWeighted
        cv2.fillPoly(road_background, [left_lane], color=[255, 255, 255])
        cv2.fillPoly(road_background, [right_lane], color=[255, 255, 255])

        road_inv_warped = cv2.warpPerspective(road, Minv, img_size, flags=cv2.INTER_LINEAR)
        road_inv_warped_background = cv2.warpPerspective(road_background, Minv, img_size, flags=cv2.INTER_LINEAR)
        
        # Draw lines back on image
        base = cv2.addWeighted(img, 1.0, road_inv_warped_background, -1.0, 0.0)        
        tracked_result = cv2.addWeighted(base, 1.0, road_inv_warped, 1.0, 0.0)        
        
        xm_per_pix = curve_centers.xm_per_pixel
        ym_per_pix = curve_centers.ym_per_pixel
        
        # Calculate the offset of the car on the road
        camera_center = (left_fitx[-1] + right_fitx[-1])/2
        center_diff = (camera_center-warped.shape[1]/2)*xm_per_pix
        side_pos = 'left'
        if center_diff <= 0:
            side_pos = 'right'
        
        ## Radius of Curvature (Resource: http://www.intmath.com/applications-differentiation/8-radius-curvature.php)
        curve_fit_cr =np.polyfit(np.array(res_yvals, np.float32)*ym_per_pix, 
                                 np.array(left_x, np.float32)*xm_per_pix, 2)
        
        # Note: Calculated using the left lane line
        curve_rad = ((1 + (2*curve_fit_cr[0]*yvals[-1]*ym_per_pix + 
                           curve_fit_cr[1])**2)**1.5)/np.absolute(2*curve_fit_cr[0])
        
        # Draw the radius of curvature, offset, and speed
        cv2.putText(tracked_result, 'Radius of Curvature = ' + str(round(curve_rad, 3)) + '(m)', 
                    (50,50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
        cv2.putText(tracked_result, 'Vehicle is ' + str(abs(round(center_diff, 3))) + 'm '+ side_pos 
                    + ' of center', (50,100), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
        
        ## Save Transitional Images Generated and Results to Output Directory ##
        undistorted_img_path = "{}{}{}{}{}".format(WORKING_DIRECTORY, OUTPUT_DIRECTORY, UNDISTORTED_PREFIX
                                                  ,str(idx), IMAGE_EXTENSION)
        color_stacked_img_path = "{}{}{}{}{}".format(WORKING_DIRECTORY, OUTPUT_DIRECTORY, COLOR_STACKED_PREFIX
                                                  ,str(idx), IMAGE_EXTENSION)
        thresholded_img_path = "{}{}{}{}{}".format(WORKING_DIRECTORY, OUTPUT_DIRECTORY, THRESHOLDING_PREFIX
                                                  ,str(idx), IMAGE_EXTENSION)
        warped_img_path = "{}{}{}{}{}".format(WORKING_DIRECTORY, OUTPUT_DIRECTORY, WARPED_PREFIX
                                                  ,str(idx), IMAGE_EXTENSION)
        lined_img_path = "{}{}{}{}{}".format(WORKING_DIRECTORY, OUTPUT_DIRECTORY, LINES_DRAWN_PREFIX
                                                  ,str(idx), IMAGE_EXTENSION)
        tracked_img_path = "{}{}{}{}{}".format(WORKING_DIRECTORY, OUTPUT_DIRECTORY, TRACKED_PREFIX
                                                  ,str(idx), IMAGE_EXTENSION)
    
        os.makedirs(os.path.join(WORKING_DIRECTORY, OUTPUT_DIRECTORY), exist_ok=True)

        print('')
        print('Saving Undistorted Result image:', undistorted_img_path)
        img = cv2.cvtColor(np.copy(img), cv2.COLOR_BGR2RGB)
        cv2.imwrite(undistorted_img_path, img)

        print('Saving Color Stacked image:', color_stacked_img_path)
        mpimg.imsave(color_stacked_img_path, color_binary)

        print('Saving Thresholded image:', thresholded_img_path)
        mpimg.imsave(thresholded_img_path, preprocessed_img, cmap='gray')
        
        print('Saving Warped image:', warped_img_path)
        mpimg.imsave(warped_img_path, warped, cmap='gray')
        
        print('Saving Curved Lines Drawn on Warped image:', lined_img_path)
        mpimg.imsave(lined_img_path, result)
        
        print('Saving Resulting Tracked Image Drawn on Warped image:', tracked_img_path)
        mpimg.imsave(tracked_img_path, tracked_result)
    
        # Plot Transitional Images for Analysis
        f, ((ax0, ax1, ax2, ax3), (ax4, ax5, ax6, ax7)) = plt.subplots(2, 4, figsize=(48, 25))
        f.tight_layout()
        
        img = cv2.cvtColor(np.copy(img), cv2.COLOR_BGR2RGB)
        ax0.imshow(img)
        ax0.set_title('Undistorted Image_'+str(idx), fontsize=40)
        
        ax1.imshow(color_binary)
        ax1.set_title('Color Maps Thresholded', fontsize=40)

        ax2.imshow(preprocessed_img, cmap='gray')
        ax2.set_title('Combined Gradients', fontsize=40)
        
        ax3.imshow(warped, cmap='gray')
        ax3.set_title('Perspective Transforms', fontsize=40)
        
        # Inverse Warped Image
        inv_warped = cv2.warpPerspective(warped, Minv, img_size, flags=cv2.INTER_LINEAR)
        ax4.imshow(inv_warped, cmap='gray')
        ax4.set_title('Inverted Warped Image_'+str(idx), fontsize=40)
        
        # Calculate Histogram
        warped_mid_y = warped.shape[0]//4
        histogram = np.sum(warped[warped_mid_y:,:], axis=0)
        ax5.plot(histogram)
        ax5.set_title('Histogram of Warped', fontsize=40)
        
        # Print Final Result
        ax6.imshow(result)
        ax6.set_title('Warped - Curved Lines Drawn', fontsize=40)
        
        # Print Final Tracked Result
        ax7.imshow(tracked_result, cmap='gray')
        ax7.set_title('Result - Tracked Image', fontsize=40)
        
        # Adjust subplots
        plt.subplots_adjust(left=0., right=1, top=0.99, bottom=0.)
        
    # Save to Picklefile
    pickle.dump(M_pickle , open( M_pickle_file, "wb" ) )
In [31]:
pipeline(test_images)
Saving Undistorted Result image: data/output_images/undistorted0.jpg
Saving Color Stacked image: data/output_images/color_stacked0.jpg
Saving Thresholded image: data/output_images/thresholded0.jpg
Saving Warped image: data/output_images/warped0.jpg
Saving Curved Lines Drawn on Warped image: data/output_images/green_lines0.jpg
Saving Resulting Tracked Image Drawn on Warped image: data/output_images/tracked0.jpg

Saving Undistorted Result image: data/output_images/undistorted1.jpg
Saving Color Stacked image: data/output_images/color_stacked1.jpg
Saving Thresholded image: data/output_images/thresholded1.jpg
Saving Warped image: data/output_images/warped1.jpg
Saving Curved Lines Drawn on Warped image: data/output_images/green_lines1.jpg
Saving Resulting Tracked Image Drawn on Warped image: data/output_images/tracked1.jpg

Saving Undistorted Result image: data/output_images/undistorted2.jpg
Saving Color Stacked image: data/output_images/color_stacked2.jpg
Saving Thresholded image: data/output_images/thresholded2.jpg
Saving Warped image: data/output_images/warped2.jpg
Saving Curved Lines Drawn on Warped image: data/output_images/green_lines2.jpg
Saving Resulting Tracked Image Drawn on Warped image: data/output_images/tracked2.jpg

Saving Undistorted Result image: data/output_images/undistorted3.jpg
Saving Color Stacked image: data/output_images/color_stacked3.jpg
Saving Thresholded image: data/output_images/thresholded3.jpg
Saving Warped image: data/output_images/warped3.jpg
Saving Curved Lines Drawn on Warped image: data/output_images/green_lines3.jpg
Saving Resulting Tracked Image Drawn on Warped image: data/output_images/tracked3.jpg

Saving Undistorted Result image: data/output_images/undistorted4.jpg
Saving Color Stacked image: data/output_images/color_stacked4.jpg
Saving Thresholded image: data/output_images/thresholded4.jpg
Saving Warped image: data/output_images/warped4.jpg
Saving Curved Lines Drawn on Warped image: data/output_images/green_lines4.jpg
Saving Resulting Tracked Image Drawn on Warped image: data/output_images/tracked4.jpg

Saving Undistorted Result image: data/output_images/undistorted5.jpg
Saving Color Stacked image: data/output_images/color_stacked5.jpg
Saving Thresholded image: data/output_images/thresholded5.jpg
Saving Warped image: data/output_images/warped5.jpg
Saving Curved Lines Drawn on Warped image: data/output_images/green_lines5.jpg
Saving Resulting Tracked Image Drawn on Warped image: data/output_images/tracked5.jpg

Saving Undistorted Result image: data/output_images/undistorted6.jpg
Saving Color Stacked image: data/output_images/color_stacked6.jpg
Saving Thresholded image: data/output_images/thresholded6.jpg
Saving Warped image: data/output_images/warped6.jpg
Saving Curved Lines Drawn on Warped image: data/output_images/green_lines6.jpg
Saving Resulting Tracked Image Drawn on Warped image: data/output_images/tracked6.jpg

Saving Undistorted Result image: data/output_images/undistorted7.jpg
Saving Color Stacked image: data/output_images/color_stacked7.jpg
Saving Thresholded image: data/output_images/thresholded7.jpg
Saving Warped image: data/output_images/warped7.jpg
Saving Curved Lines Drawn on Warped image: data/output_images/green_lines7.jpg
Saving Resulting Tracked Image Drawn on Warped image: data/output_images/tracked7.jpg

Saving Undistorted Result image: data/output_images/undistorted8.jpg
Saving Color Stacked image: data/output_images/color_stacked8.jpg
Saving Thresholded image: data/output_images/thresholded8.jpg
Saving Warped image: data/output_images/warped8.jpg
Saving Curved Lines Drawn on Warped image: data/output_images/green_lines8.jpg
Saving Resulting Tracked Image Drawn on Warped image: data/output_images/tracked8.jpg

Saving Undistorted Result image: data/output_images/undistorted9.jpg
Saving Color Stacked image: data/output_images/color_stacked9.jpg
Saving Thresholded image: data/output_images/thresholded9.jpg
Saving Warped image: data/output_images/warped9.jpg
Saving Curved Lines Drawn on Warped image: data/output_images/green_lines9.jpg
Saving Resulting Tracked Image Drawn on Warped image: data/output_images/tracked9.jpg

Saving Undistorted Result image: data/output_images/undistorted10.jpg
Saving Color Stacked image: data/output_images/color_stacked10.jpg
Saving Thresholded image: data/output_images/thresholded10.jpg
Saving Warped image: data/output_images/warped10.jpg
Saving Curved Lines Drawn on Warped image: data/output_images/green_lines10.jpg
Saving Resulting Tracked Image Drawn on Warped image: data/output_images/tracked10.jpg

Saving Undistorted Result image: data/output_images/undistorted11.jpg
Saving Color Stacked image: data/output_images/color_stacked11.jpg
Saving Thresholded image: data/output_images/thresholded11.jpg
Saving Warped image: data/output_images/warped11.jpg
Saving Curved Lines Drawn on Warped image: data/output_images/green_lines11.jpg
Saving Resulting Tracked Image Drawn on Warped image: data/output_images/tracked11.jpg

Analyze Histogram of Difficult Warped Images

In order to determine the correct thresholds and hyperparameters to detect the lane lines, I included this code cell to analyze the more difficult images. For example, if the video had a few frames that did not track the lane lines well, I would would create a snapshot of a single frame and then try and tweak the parameters until the lane was in an acceptable range.

In [16]:
## Analyze Error Prone Lanes ## 
# Load Picklefiles
dist_pickle = pickle.load( open(dist_pickle_file, "rb"))
M_pickle = pickle.load( open(M_pickle_file, "rb"))

# Load Most Difficult Image to process
filename = TEST_IMAGES_PREFIX+'2'+IMAGE_EXTENSION # First two images are 'straight lines' 
M_str = "M_" + filename
Minv_str = "Minv_" + filename
M = M_pickle[M_str]
Minv = M_pickle[Minv_str]

# Load Warped Image
warped_img_path = os.path.join(WORKING_DIRECTORY, OUTPUT_DIRECTORY, WARPED_PREFIX+'0'+IMAGE_EXTENSION)
warped = mpimg.imread(warped_img_path)
warped = cv2.cvtColor(warped, cv2.COLOR_RGB2GRAY)

# Inverse Warpe Image
inv_warped = cv2.warpPerspective(warped, Minv, img_size, flags=cv2.INTER_LINEAR)

# Plot Histogram of Test Image
f, ((ax0, ax1, ax2)) = plt.subplots(1, 3, figsize=(24, 9))
f.tight_layout()

ax0.imshow(warped, cmap='gray')
ax0.set_title('Warped Image', fontsize=40)

ax1.imshow(inv_warped, cmap='gray')
ax1.set_title('Inverted Warped Mask', fontsize=40)

# Calculate Histogram
warped_mid_y = warped.shape[0]//4
histogram = np.sum(warped[warped_mid_y:,:], axis=0)
ax2.plot(histogram)
ax2.set_title('Histogram of Warped', fontsize=40)

plt.subplots_adjust(left=0., right=1, top=0.9, bottom=0.)

Video Generation

In [29]:
def process_image(image):
    if image is not None:
        global COUNTER
        global TRACKER
        color_image = np.copy(image)
        INPUT_DIR = 'data/output_images/processed/'
        os.makedirs(INPUT_DIR, exist_ok=True)
        im = Image.fromarray(color_image)
        im.save(INPUT_DIR+"video_image_" + str(COUNTER)+".jpg")
        

        # Load Calibration Picklefile
        dist_pickle = pickle.load( open(dist_pickle_file, "rb"))
        mtx = dist_pickle["mtx"]
        dist = dist_pickle["dist"]

        # Undistort the image
        img = cv2.undistort(image, mtx, dist, None, mtx)
        color_binary, preprocessed_img = apply_thresholds(img)
        color_stacked_img_path = "{}{}".format(INPUT_DIR, COLOR_STACKED_PREFIX+
                                                   str(COUNTER)+IMAGE_EXTENSION)
        mpimg.imsave(color_stacked_img_path, color_binary)
        
        ## Save Thresholded ##
        thresholded_img_path = "{}{}".format(INPUT_DIR, THRESHOLDING_PREFIX+
                                                   str(COUNTER)+IMAGE_EXTENSION)
        
        # Making the original road pixels 3 color channels
        mpimg.imsave(thresholded_img_path, preprocessed_img, cmap='gray')

        # Perspective Transforms of Image
        img_size = (img.shape[1], img.shape[0])

        ## Perform Perspective Transform ##
        M, Minv, warped = apply_perspective_transform(preprocessed_img)

        # Instantiate Tracker() class for lane tracking
        window_width = warped.shape[1]//20 
        window_height = warped.shape[0]//12 
        real_to_pix_x = 3.7/650
        real_to_pix_y = 30./720

        # Use tracking function to find centroids for drawing lane lines
        if TRACKER is None:
            TRACKER = tracker(win_width=window_width, win_height=window_height, margin = 25,
                                y_m = real_to_pix_y, x_m = real_to_pix_x, smoothing_factor = 38)
            curve_centers = TRACKER
        else:
            curve_centers = TRACKER
        
        window_centroids = curve_centers.find_window_centroids(warped)

        # Points used to draw all the left and right windows
        l_points = np.zeros_like(warped)
        r_points = np.zeros_like(warped)

        # Points used to find the left and right lanes
        right_x = []
        left_x = []

        # Go through even levels and draw the windows
        for level in range(0,len(window_centroids)):
            # Utilize window_mask function above to draw window areas
            l_mask = window_mask(window_width, window_height, warped, window_centroids[level][0], level)
            r_mask = window_mask(window_width, window_height, warped, window_centroids[level][1], level)

            # Add center value found in frame to the list of lane points per left, right
            left_x.append(window_centroids[level][0])
            right_x.append(window_centroids[level][1])

            # Add graphic points from window mask here to total pixels found
            l_points[(l_points == 255) | ((l_mask == 1.))] = 255
            r_points[(r_points == 255) | ((r_mask == 1.))] = 255

        ## Draw the results back on Image ##
        # Add both left and right pixels together
        template = np.array(r_points+l_points, np.uint8)

        # Create a zero color channel
        zero_channel = np.zeros_like(template)

        # Make window pixels green
        template = np.array(cv2.merge((zero_channel, template, zero_channel)), np.uint8)
        warped = denormalize_pixels(warped)

        # Making the original road pixels 3 color channels
        warpage = np.array(cv2.merge((warped, warped, warped)), np.uint8)        

        # Overlay the original road image with window results
        result = cv2.addWeighted(warpage, 1, template, 0.5, 0.)

        # Fit the lane boundaries to the left, right, and center positions
        yvals = range(0, warped.shape[0])
        res_yvals = np.arange(warped.shape[0]-(window_height/2),0,-window_height)

        left_fit = np.polyfit(res_yvals, left_x, 2)
        # Degree 2 polynomial
        left_fitx = left_fit[0]*yvals*yvals + left_fit[1]*yvals + left_fit[2]
        left_fitx = np.array(left_fitx, np.int32)

        right_fit = np.polyfit(res_yvals, right_x, 2)
        # Degree 2 polynomial
        right_fitx = right_fit[0]*yvals*yvals + right_fit[1]*yvals + right_fit[2]
        right_fitx = np.array(right_fitx, np.int32)

        # Restructure/Encapsulate array values (to make it pretty)
        left_lane = np.array(list(zip(np.concatenate((left_fitx-window_width/2, left_fitx[::-1]+window_width/2), axis=0),
                                     np.concatenate((yvals, yvals[::-1]), axis=0))), np.int32)
        right_lane = np.array(list(zip(np.concatenate((right_fitx-window_width/2, right_fitx[::-1]+window_width/2), axis=0),
                                      np.concatenate((yvals, yvals[::-1]), axis=0))), np.int32)
        middle_lane = np.array(list(zip(np.concatenate((right_fitx-window_width/2, right_fitx[::-1]+window_width/2), axis=0),
                                       np.concatenate((yvals, yvals[::-1]), axis=0))), np.int32)

        # Recast x and y points
        pts_left = np.array([np.transpose(np.vstack([left_fitx, yvals]))])
        pts_right = np.array([np.flipud(np.transpose(np.vstack([right_fitx, yvals])))])
        pts = np.hstack((pts_left, pts_right))

        road = np.zeros_like(img)
        road_background = np.zeros_like(img)

        # Draw the lane onto the warped blank image
        cv2.fillPoly(road, np.int_([pts]), (0,200, 200))
        cv2.fillPoly(road, [left_lane], color=[255,0, 50])
        cv2.fillPoly(road, [right_lane], color=[50, 0, 255])

        # Use these to make negate pixels during cv2.addWeighted
        cv2.fillPoly(road_background, [left_lane], color=[255, 255, 255])
        cv2.fillPoly(road_background, [right_lane], color=[255, 255, 255])

        road_inv_warped = cv2.warpPerspective(road, Minv, img_size, flags=cv2.INTER_LINEAR)
        road_inv_warped_background = cv2.warpPerspective(road_background, Minv, img_size, flags=cv2.INTER_LINEAR)

        # Draw lines back on image
        base = cv2.addWeighted(img, 1.0, road_inv_warped_background, -1.0, 0.0)        
        tracked_result = cv2.addWeighted(base, 1.0, road_inv_warped, 1.0, 0.0)        

        xm_per_pix = curve_centers.xm_per_pixel
        ym_per_pix = curve_centers.ym_per_pixel

        # Calculate the offset of the car on the road
        camera_center = (left_fitx[-1] + right_fitx[-1])/2
        center_diff = (camera_center-warped.shape[1]/2)*xm_per_pix
        side_pos = 'left'
        if center_diff <= 0:
            side_pos = 'right'

        ## Radius of Curvature (Resource: http://www.intmath.com/applications-differentiation/8-radius-curvature.php)
        curve_fit_cr =np.polyfit(np.array(res_yvals, np.float32)*ym_per_pix, 
                                 np.array(left_x, np.float32)*xm_per_pix, 2)

        # Note: Calculated using the left lane line
        curve_rad = ((1 + (2*curve_fit_cr[0]*yvals[-1]*ym_per_pix + 
                           curve_fit_cr[1])**2)**1.5)/np.absolute(2*curve_fit_cr[0])


        # Draw the radius of curvature, offset, and speed
        cv2.putText(tracked_result, 'Radius of Curvature = ' + str(round(curve_rad, 4)) + '(m)', 
                    (50,50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
        cv2.putText(tracked_result, 'Vehicle is ' + str(abs(round(center_diff, 3))) + 'm '+ side_pos 
                    + ' of center', (50,100), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
        ## Increase COUNTER ##
        COUNTER+=1
        # Return Tracked result
        return tracked_result
    else:
        return image

Process Video

In [31]:
#Import packages to edit/save/watch video clips
from moviepy.editor import VideoFileClip
from moviepy.editor import ImageSequenceClip
from moviepy.editor import CompositeVideoClip

from IPython.display import HTML
from PIL import Image
import shutil

## Constants ##
# Video Filenames #
CHALLENGE_VIDEO = 'challenge_video.mp4'
PROJECT_VIDEO = 'project_video.mp4'
HARDER_CHALLENGE_VIDEO = 'harder_challenge_video.mp4'
# Input path
VIDEO_FILE_PATH = os.path.join(WORKING_DIRECTORY, PROJECT_VIDEO)
# Output Path
VIDEO_OUTPUT_PATH = os.path.join(WORKING_DIRECTORY, OUTPUT_DIRECTORY, 'processed_'+PROJECT_VIDEO)

## Process Videos ##
clip = VideoFileClip(VIDEO_FILE_PATH)
subclip = VideoFileClip(VIDEO_FILE_PATH) #.subclip(37,42)
TRACKER = None
COUNTER = 0
project_clip = subclip.fl_image(process_image)
#%time

## Gather processed images ##
INPUT_DIR = 'data/output_images/processed/'
color_imgs = []
preprocessed_imgs = []
print('frames: ', int(subclip.fps * subclip.duration))
for ind in range(0, int(subclip.fps * subclip.duration)):
    color_stacked_img_path = "{}{}".format(INPUT_DIR, COLOR_STACKED_PREFIX+
                                                   str(ind)+'.jpg')
    thresholded_img_path = "{}{}".format(INPUT_DIR, THRESHOLDING_PREFIX+
                                               str(ind)+'.jpg')
    if os.path.exists(color_stacked_img_path):
        color_imgs.append(color_stacked_img_path)
    if os.path.exists(thresholded_img_path):
        preprocessed_imgs.append(thresholded_img_path)

# Create Composite Video of Color Binary Images
clip2 = ImageSequenceClip(color_imgs, fps = subclip.fps)
color_binary_clip = clip2.resize(0.25)

# Create Composite Video of Thresholded Images
clip3 = ImageSequenceClip(preprocessed_imgs, fps = subclip.fps)
thresholded_clip = clip3.resize(0.25)

## Process Composite Videos ##
video = CompositeVideoClip([project_clip,
                           color_binary_clip.set_pos((640,0)),
                           thresholded_clip.set_pos(("right","top"))])

## Save Video File to Output Directory ##
os.makedirs(os.path.join(WORKING_DIRECTORY, OUTPUT_DIRECTORY), exist_ok=True)
# Output Path
VIDEO_OUTPUT_PATH = os.path.join(WORKING_DIRECTORY, OUTPUT_DIRECTORY, 'comp_processed_'+PROJECT_VIDEO)
video.write_videofile(VIDEO_OUTPUT_PATH, audio=False)

# Format Output Path
HTML("""
<video width="960" height="540" controls>
 <source src="{0}">
</video>
""".format(VIDEO_OUTPUT_PATH))
frames:  1260
[MoviePy] >>>> Building video data/output_images/comp_processed_project_video.mp4
[MoviePy] Writing video data/output_images/comp_processed_project_video.mp4

  0%|          | 0/1261 [00:00<?, ?it/s]

  0%|          | 1/1261 [00:01<32:23,  1.54s/it]

  0%|          | 2/1261 [00:02<31:09,  1.48s/it]

  0%|          | 3/1261 [00:04<32:38,  1.56s/it]

  0%|          | 4/1261 [00:06<36:24,  1.74s/it]

  0%|          | 5/1261 [00:08<35:24,  1.69s/it]

  0%|          | 6/1261 [00:09<32:51,  1.57s/it]

  1%|          | 7/1261 [00:10<31:04,  1.49s/it]

  1%|          | 8/1261 [00:12<31:06,  1.49s/it]

  1%|          | 9/1261 [00:13<29:53,  1.43s/it]

  1%|          | 10/1261 [00:15<28:57,  1.39s/it]

  1%|          | 11/1261 [00:16<28:14,  1.36s/it]

  1%|          | 12/1261 [00:17<27:08,  1.30s/it]

  1%|          | 13/1261 [00:18<27:01,  1.30s/it]

  1%|          | 14/1261 [00:19<26:15,  1.26s/it]

  1%|          | 15/1261 [00:21<26:42,  1.29s/it]

  1%|▏         | 16/1261 [00:22<26:34,  1.28s/it]

  1%|▏         | 17/1261 [00:23<26:09,  1.26s/it]

  1%|▏         | 18/1261 [00:25<26:06,  1.26s/it]

  2%|▏         | 19/1261 [00:26<25:40,  1.24s/it]

  2%|▏         | 20/1261 [00:27<25:28,  1.23s/it]

  2%|▏         | 21/1261 [00:28<24:57,  1.21s/it]

  2%|▏         | 22/1261 [00:29<24:40,  1.19s/it]

  2%|▏         | 23/1261 [00:30<23:40,  1.15s/it]

  2%|▏         | 24/1261 [00:31<23:25,  1.14s/it]

  2%|▏         | 25/1261 [00:33<23:31,  1.14s/it]

  2%|▏         | 26/1261 [00:34<23:58,  1.16s/it]

  2%|▏         | 27/1261 [00:35<23:23,  1.14s/it]

  2%|▏         | 28/1261 [00:36<23:14,  1.13s/it]

  2%|▏         | 29/1261 [00:37<23:24,  1.14s/it]

  2%|▏         | 30/1261 [00:38<23:33,  1.15s/it]

  2%|▏         | 31/1261 [00:39<23:27,  1.14s/it]

  3%|▎         | 32/1261 [00:41<23:26,  1.14s/it]

  3%|▎         | 33/1261 [00:42<23:33,  1.15s/it]

  3%|▎         | 34/1261 [00:43<23:37,  1.15s/it]

  3%|▎         | 35/1261 [00:44<23:04,  1.13s/it]

  3%|▎         | 36/1261 [00:45<22:36,  1.11s/it]

  3%|▎         | 37/1261 [00:46<23:13,  1.14s/it]

  3%|▎         | 38/1261 [00:47<23:16,  1.14s/it]

  3%|▎         | 39/1261 [00:48<22:46,  1.12s/it]

  3%|▎         | 40/1261 [00:50<23:11,  1.14s/it]

  3%|▎         | 41/1261 [00:51<23:00,  1.13s/it]

  3%|▎         | 42/1261 [00:52<22:53,  1.13s/it]

  3%|▎         | 43/1261 [00:53<22:59,  1.13s/it]

  3%|▎         | 44/1261 [00:54<22:49,  1.13s/it]

  4%|▎         | 45/1261 [00:55<23:14,  1.15s/it]

  4%|▎         | 46/1261 [00:56<22:59,  1.14s/it]

  4%|▎         | 47/1261 [00:58<22:37,  1.12s/it]

  4%|▍         | 48/1261 [00:59<22:49,  1.13s/it]

  4%|▍         | 49/1261 [01:00<22:46,  1.13s/it]

  4%|▍         | 50/1261 [01:01<22:42,  1.13s/it]

  4%|▍         | 51/1261 [01:02<24:00,  1.19s/it]

  4%|▍         | 52/1261 [01:04<24:45,  1.23s/it]

  4%|▍         | 53/1261 [01:05<24:34,  1.22s/it]

  4%|▍         | 54/1261 [01:06<23:57,  1.19s/it]

  4%|▍         | 55/1261 [01:07<23:01,  1.15s/it]

  4%|▍         | 56/1261 [01:08<23:22,  1.16s/it]

  5%|▍         | 57/1261 [01:09<22:32,  1.12s/it]

  5%|▍         | 58/1261 [01:10<21:36,  1.08s/it]

  5%|▍         | 59/1261 [01:15<46:59,  2.35s/it]

  5%|▍         | 60/1261 [01:16<39:05,  1.95s/it]

  5%|▍         | 61/1261 [01:18<33:32,  1.68s/it]

  5%|▍         | 62/1261 [01:19<29:41,  1.49s/it]

  5%|▍         | 63/1261 [01:20<26:45,  1.34s/it]

  5%|▌         | 64/1261 [01:21<24:49,  1.24s/it]

  5%|▌         | 65/1261 [01:22<23:20,  1.17s/it]

  5%|▌         | 66/1261 [01:23<22:42,  1.14s/it]

  5%|▌         | 67/1261 [01:24<21:39,  1.09s/it]

  5%|▌         | 68/1261 [01:25<21:45,  1.09s/it]

  5%|▌         | 69/1261 [01:26<21:58,  1.11s/it]

  6%|▌         | 70/1261 [01:27<22:00,  1.11s/it]

  6%|▌         | 71/1261 [01:28<21:43,  1.10s/it]

  6%|▌         | 72/1261 [01:29<21:56,  1.11s/it]

  6%|▌         | 73/1261 [01:30<21:37,  1.09s/it]

  6%|▌         | 74/1261 [01:31<22:08,  1.12s/it]

  6%|▌         | 75/1261 [01:32<21:37,  1.09s/it]

  6%|▌         | 76/1261 [01:34<21:46,  1.10s/it]

  6%|▌         | 77/1261 [01:35<21:23,  1.08s/it]

  6%|▌         | 78/1261 [01:36<21:23,  1.08s/it]

  6%|▋         | 79/1261 [01:37<21:12,  1.08s/it]

  6%|▋         | 80/1261 [01:38<21:19,  1.08s/it]

  6%|▋         | 81/1261 [01:39<21:48,  1.11s/it]

  7%|▋         | 82/1261 [01:40<22:59,  1.17s/it]

  7%|▋         | 83/1261 [01:42<23:31,  1.20s/it]

  7%|▋         | 84/1261 [01:43<23:26,  1.20s/it]

  7%|▋         | 85/1261 [01:44<22:29,  1.15s/it]

  7%|▋         | 86/1261 [01:45<22:35,  1.15s/it]

  7%|▋         | 87/1261 [01:46<22:03,  1.13s/it]

  7%|▋         | 88/1261 [01:47<21:35,  1.10s/it]

  7%|▋         | 89/1261 [01:48<21:28,  1.10s/it]

  7%|▋         | 90/1261 [01:49<21:41,  1.11s/it]

  7%|▋         | 91/1261 [01:51<24:00,  1.23s/it]

  7%|▋         | 92/1261 [01:52<24:16,  1.25s/it]

  7%|▋         | 93/1261 [01:54<25:09,  1.29s/it]

  7%|▋         | 94/1261 [01:55<24:14,  1.25s/it]

  8%|▊         | 95/1261 [01:56<22:56,  1.18s/it]

  8%|▊         | 96/1261 [01:57<22:39,  1.17s/it]

  8%|▊         | 97/1261 [01:58<21:47,  1.12s/it]

  8%|▊         | 98/1261 [01:59<21:56,  1.13s/it]

  8%|▊         | 99/1261 [02:00<21:31,  1.11s/it]

  8%|▊         | 100/1261 [02:01<21:26,  1.11s/it]

  8%|▊         | 101/1261 [02:02<21:33,  1.12s/it]

  8%|▊         | 102/1261 [02:04<23:02,  1.19s/it]

  8%|▊         | 103/1261 [02:05<23:16,  1.21s/it]

  8%|▊         | 104/1261 [02:06<23:13,  1.20s/it]

  8%|▊         | 105/1261 [02:07<22:29,  1.17s/it]

  8%|▊         | 106/1261 [02:08<22:26,  1.17s/it]

  8%|▊         | 107/1261 [02:09<21:35,  1.12s/it]

  9%|▊         | 108/1261 [02:10<21:26,  1.12s/it]

  9%|▊         | 109/1261 [02:12<21:13,  1.11s/it]

  9%|▊         | 110/1261 [02:13<21:04,  1.10s/it]

  9%|▉         | 111/1261 [02:14<20:57,  1.09s/it]

  9%|▉         | 112/1261 [02:15<23:03,  1.20s/it]

  9%|▉         | 113/1261 [02:17<23:50,  1.25s/it]

  9%|▉         | 114/1261 [02:18<24:19,  1.27s/it]

  9%|▉         | 115/1261 [02:19<23:57,  1.25s/it]

  9%|▉         | 116/1261 [02:20<24:18,  1.27s/it]

  9%|▉         | 117/1261 [02:22<26:19,  1.38s/it]

  9%|▉         | 118/1261 [02:23<25:00,  1.31s/it]

  9%|▉         | 119/1261 [02:25<27:34,  1.45s/it]

 10%|▉         | 120/1261 [02:26<26:46,  1.41s/it]

 10%|▉         | 121/1261 [02:27<25:44,  1.35s/it]

 10%|▉         | 122/1261 [02:29<25:48,  1.36s/it]

 10%|▉         | 123/1261 [02:30<24:43,  1.30s/it]

 10%|▉         | 124/1261 [02:31<23:33,  1.24s/it]

 10%|▉         | 125/1261 [02:32<22:36,  1.19s/it]

 10%|▉         | 126/1261 [02:33<22:00,  1.16s/it]

 10%|█         | 127/1261 [02:34<21:21,  1.13s/it]

 10%|█         | 128/1261 [02:36<21:39,  1.15s/it]

 10%|█         | 129/1261 [02:37<22:28,  1.19s/it]

 10%|█         | 130/1261 [02:38<21:53,  1.16s/it]

 10%|█         | 131/1261 [02:39<21:30,  1.14s/it]

 10%|█         | 132/1261 [02:40<21:10,  1.13s/it]

 11%|█         | 133/1261 [02:41<21:02,  1.12s/it]

 11%|█         | 134/1261 [02:42<20:44,  1.10s/it]

 11%|█         | 135/1261 [02:43<20:28,  1.09s/it]

 11%|█         | 136/1261 [02:44<20:36,  1.10s/it]

 11%|█         | 137/1261 [02:46<20:26,  1.09s/it]

 11%|█         | 138/1261 [02:47<20:38,  1.10s/it]

 11%|█         | 139/1261 [02:48<20:20,  1.09s/it]

 11%|█         | 140/1261 [02:49<20:47,  1.11s/it]

 11%|█         | 141/1261 [02:50<20:29,  1.10s/it]

 11%|█▏        | 142/1261 [02:51<20:16,  1.09s/it]

 11%|█▏        | 143/1261 [02:52<20:15,  1.09s/it]

 11%|█▏        | 144/1261 [02:53<19:52,  1.07s/it]

 11%|█▏        | 145/1261 [02:54<20:00,  1.08s/it]

 12%|█▏        | 146/1261 [02:55<19:56,  1.07s/it]

 12%|█▏        | 147/1261 [02:56<19:24,  1.05s/it]

 12%|█▏        | 148/1261 [02:57<19:42,  1.06s/it]

 12%|█▏        | 149/1261 [02:58<19:29,  1.05s/it]

 12%|█▏        | 150/1261 [03:00<19:59,  1.08s/it]

 12%|█▏        | 151/1261 [03:01<19:50,  1.07s/it]

 12%|█▏        | 152/1261 [03:02<19:46,  1.07s/it]

 12%|█▏        | 153/1261 [03:03<19:49,  1.07s/it]

 12%|█▏        | 154/1261 [03:04<19:53,  1.08s/it]

 12%|█▏        | 155/1261 [03:05<19:59,  1.08s/it]

 12%|█▏        | 156/1261 [03:06<19:33,  1.06s/it]

 12%|█▏        | 157/1261 [03:07<19:55,  1.08s/it]

 13%|█▎        | 158/1261 [03:08<19:35,  1.07s/it]

 13%|█▎        | 159/1261 [03:09<19:04,  1.04s/it]

 13%|█▎        | 160/1261 [03:10<19:06,  1.04s/it]

 13%|█▎        | 161/1261 [03:11<19:07,  1.04s/it]

 13%|█▎        | 162/1261 [03:12<19:05,  1.04s/it]

 13%|█▎        | 163/1261 [03:13<18:40,  1.02s/it]

 13%|█▎        | 164/1261 [03:14<18:49,  1.03s/it]

 13%|█▎        | 165/1261 [03:15<18:37,  1.02s/it]

 13%|█▎        | 166/1261 [03:16<18:50,  1.03s/it]

 13%|█▎        | 167/1261 [03:17<18:25,  1.01s/it]

 13%|█▎        | 168/1261 [03:18<18:53,  1.04s/it]

 13%|█▎        | 169/1261 [03:19<19:03,  1.05s/it]

 13%|█▎        | 170/1261 [03:20<19:02,  1.05s/it]

 14%|█▎        | 171/1261 [03:22<19:03,  1.05s/it]

 14%|█▎        | 172/1261 [03:23<19:38,  1.08s/it]

 14%|█▎        | 173/1261 [03:24<19:08,  1.06s/it]

 14%|█▍        | 174/1261 [03:25<19:17,  1.06s/it]

 14%|█▍        | 175/1261 [03:26<18:48,  1.04s/it]

 14%|█▍        | 176/1261 [03:27<19:04,  1.05s/it]

 14%|█▍        | 177/1261 [03:28<19:10,  1.06s/it]

 14%|█▍        | 178/1261 [03:29<19:57,  1.11s/it]

 14%|█▍        | 179/1261 [03:30<20:33,  1.14s/it]

 14%|█▍        | 180/1261 [03:31<20:20,  1.13s/it]

 14%|█▍        | 181/1261 [03:33<20:29,  1.14s/it]

 14%|█▍        | 182/1261 [03:34<20:55,  1.16s/it]

 15%|█▍        | 183/1261 [03:35<20:50,  1.16s/it]

 15%|█▍        | 184/1261 [03:36<21:23,  1.19s/it]

 15%|█▍        | 185/1261 [03:37<20:58,  1.17s/it]

 15%|█▍        | 186/1261 [03:39<20:56,  1.17s/it]

 15%|█▍        | 187/1261 [03:40<20:37,  1.15s/it]

 15%|█▍        | 188/1261 [03:41<20:30,  1.15s/it]

 15%|█▍        | 189/1261 [03:42<20:09,  1.13s/it]

 15%|█▌        | 190/1261 [03:43<20:50,  1.17s/it]

 15%|█▌        | 191/1261 [03:44<20:23,  1.14s/it]

 15%|█▌        | 192/1261 [03:45<20:31,  1.15s/it]

 15%|█▌        | 193/1261 [03:46<20:03,  1.13s/it]

 15%|█▌        | 194/1261 [03:48<20:49,  1.17s/it]

 15%|█▌        | 195/1261 [03:49<20:34,  1.16s/it]

 16%|█▌        | 196/1261 [03:50<20:16,  1.14s/it]

 16%|█▌        | 197/1261 [03:51<20:22,  1.15s/it]

 16%|█▌        | 198/1261 [03:52<20:41,  1.17s/it]

 16%|█▌        | 199/1261 [03:53<20:32,  1.16s/it]

 16%|█▌        | 200/1261 [03:55<21:08,  1.20s/it]

 16%|█▌        | 201/1261 [03:56<20:36,  1.17s/it]

 16%|█▌        | 202/1261 [03:57<20:53,  1.18s/it]

 16%|█▌        | 203/1261 [03:58<20:37,  1.17s/it]

 16%|█▌        | 204/1261 [04:00<21:51,  1.24s/it]

 16%|█▋        | 205/1261 [04:01<21:17,  1.21s/it]

 16%|█▋        | 206/1261 [04:02<21:02,  1.20s/it]

 16%|█▋        | 207/1261 [04:03<20:40,  1.18s/it]

 16%|█▋        | 208/1261 [04:04<20:25,  1.16s/it]

 17%|█▋        | 209/1261 [04:05<20:07,  1.15s/it]

 17%|█▋        | 210/1261 [04:06<19:58,  1.14s/it]

 17%|█▋        | 211/1261 [04:08<19:54,  1.14s/it]

 17%|█▋        | 212/1261 [04:09<19:39,  1.12s/it]

 17%|█▋        | 213/1261 [04:10<19:30,  1.12s/it]

 17%|█▋        | 214/1261 [04:11<19:49,  1.14s/it]

 17%|█▋        | 215/1261 [04:12<19:53,  1.14s/it]

 17%|█▋        | 216/1261 [04:13<19:34,  1.12s/it]

 17%|█▋        | 217/1261 [04:14<19:24,  1.12s/it]

 17%|█▋        | 218/1261 [04:15<19:51,  1.14s/it]

 17%|█▋        | 219/1261 [04:17<20:13,  1.16s/it]

 17%|█▋        | 220/1261 [04:18<19:41,  1.14s/it]

 18%|█▊        | 221/1261 [04:19<19:50,  1.14s/it]

 18%|█▊        | 222/1261 [04:20<20:16,  1.17s/it]

 18%|█▊        | 223/1261 [04:21<19:29,  1.13s/it]

 18%|█▊        | 224/1261 [04:22<19:17,  1.12s/it]

 18%|█▊        | 225/1261 [04:23<19:16,  1.12s/it]

 18%|█▊        | 226/1261 [04:25<19:23,  1.12s/it]

 18%|█▊        | 227/1261 [04:26<19:11,  1.11s/it]

 18%|█▊        | 228/1261 [04:27<19:26,  1.13s/it]

 18%|█▊        | 229/1261 [04:28<19:08,  1.11s/it]

 18%|█▊        | 230/1261 [04:29<18:53,  1.10s/it]

 18%|█▊        | 231/1261 [04:30<18:55,  1.10s/it]

 18%|█▊        | 232/1261 [04:31<18:53,  1.10s/it]

 18%|█▊        | 233/1261 [04:32<18:44,  1.09s/it]

 19%|█▊        | 234/1261 [04:33<18:55,  1.11s/it]

 19%|█▊        | 235/1261 [04:34<18:57,  1.11s/it]

 19%|█▊        | 236/1261 [04:36<18:44,  1.10s/it]

 19%|█▉        | 237/1261 [04:37<18:32,  1.09s/it]

 19%|█▉        | 238/1261 [04:38<18:34,  1.09s/it]

 19%|█▉        | 239/1261 [04:39<18:42,  1.10s/it]

 19%|█▉        | 240/1261 [04:40<18:31,  1.09s/it]

 19%|█▉        | 241/1261 [04:41<18:52,  1.11s/it]

 19%|█▉        | 242/1261 [04:42<18:47,  1.11s/it]

 19%|█▉        | 243/1261 [04:43<18:53,  1.11s/it]

 19%|█▉        | 244/1261 [04:44<18:34,  1.10s/it]

 19%|█▉        | 245/1261 [04:45<18:19,  1.08s/it]

 20%|█▉        | 246/1261 [04:46<18:33,  1.10s/it]

 20%|█▉        | 247/1261 [04:48<18:39,  1.10s/it]

 20%|█▉        | 248/1261 [04:49<18:23,  1.09s/it]

 20%|█▉        | 249/1261 [04:50<18:15,  1.08s/it]

 20%|█▉        | 250/1261 [04:51<18:05,  1.07s/it]

 20%|█▉        | 251/1261 [04:52<17:52,  1.06s/it]

 20%|█▉        | 252/1261 [04:53<18:36,  1.11s/it]

 20%|██        | 253/1261 [04:54<18:32,  1.10s/it]

 20%|██        | 254/1261 [04:55<18:51,  1.12s/it]

 20%|██        | 255/1261 [04:56<19:00,  1.13s/it]

 20%|██        | 256/1261 [04:58<18:51,  1.13s/it]

 20%|██        | 257/1261 [04:59<18:41,  1.12s/it]

 20%|██        | 258/1261 [05:00<18:41,  1.12s/it]

 21%|██        | 259/1261 [05:01<18:27,  1.11s/it]

 21%|██        | 260/1261 [05:02<18:40,  1.12s/it]

 21%|██        | 261/1261 [05:03<19:05,  1.15s/it]

 21%|██        | 262/1261 [05:05<20:39,  1.24s/it]

 21%|██        | 263/1261 [05:07<23:39,  1.42s/it]

 21%|██        | 264/1261 [05:08<23:18,  1.40s/it]

 21%|██        | 265/1261 [05:09<23:18,  1.40s/it]

 21%|██        | 266/1261 [05:11<24:52,  1.50s/it]

 21%|██        | 267/1261 [05:13<25:19,  1.53s/it]

 21%|██▏       | 268/1261 [05:15<28:09,  1.70s/it]

 21%|██▏       | 269/1261 [05:16<25:41,  1.55s/it]

 21%|██▏       | 270/1261 [05:17<25:02,  1.52s/it]

 21%|██▏       | 271/1261 [05:19<25:01,  1.52s/it]

 22%|██▏       | 272/1261 [05:20<24:53,  1.51s/it]

 22%|██▏       | 273/1261 [05:22<23:12,  1.41s/it]

 22%|██▏       | 274/1261 [05:23<23:09,  1.41s/it]

 22%|██▏       | 275/1261 [05:26<29:41,  1.81s/it]

 22%|██▏       | 276/1261 [05:28<34:00,  2.07s/it]

 22%|██▏       | 277/1261 [05:30<33:49,  2.06s/it]

 22%|██▏       | 278/1261 [05:32<33:50,  2.07s/it]

 22%|██▏       | 279/1261 [05:34<30:17,  1.85s/it]

 22%|██▏       | 280/1261 [05:36<30:48,  1.88s/it]

 22%|██▏       | 281/1261 [05:38<30:19,  1.86s/it]

 22%|██▏       | 282/1261 [05:39<30:00,  1.84s/it]

 22%|██▏       | 283/1261 [05:41<26:57,  1.65s/it]

 23%|██▎       | 284/1261 [05:42<24:30,  1.51s/it]

 23%|██▎       | 285/1261 [05:43<22:24,  1.38s/it]

 23%|██▎       | 286/1261 [05:44<21:14,  1.31s/it]

 23%|██▎       | 287/1261 [05:45<20:31,  1.26s/it]

 23%|██▎       | 288/1261 [05:47<23:31,  1.45s/it]

 23%|██▎       | 289/1261 [05:49<25:20,  1.56s/it]

 23%|██▎       | 290/1261 [05:51<27:21,  1.69s/it]

 23%|██▎       | 291/1261 [05:52<25:34,  1.58s/it]

 23%|██▎       | 292/1261 [05:53<24:03,  1.49s/it]

 23%|██▎       | 293/1261 [05:55<23:06,  1.43s/it]

 23%|██▎       | 294/1261 [05:56<22:10,  1.38s/it]

 23%|██▎       | 295/1261 [05:57<21:29,  1.34s/it]

 23%|██▎       | 296/1261 [05:59<21:20,  1.33s/it]

 24%|██▎       | 297/1261 [06:00<20:49,  1.30s/it]

 24%|██▎       | 298/1261 [06:01<20:36,  1.28s/it]

 24%|██▎       | 299/1261 [06:02<20:37,  1.29s/it]

 24%|██▍       | 300/1261 [06:04<20:20,  1.27s/it]

 24%|██▍       | 301/1261 [06:05<20:01,  1.25s/it]

 24%|██▍       | 302/1261 [06:06<20:29,  1.28s/it]

 24%|██▍       | 303/1261 [06:07<20:19,  1.27s/it]

 24%|██▍       | 304/1261 [06:09<20:33,  1.29s/it]

 24%|██▍       | 305/1261 [06:10<21:03,  1.32s/it]

 24%|██▍       | 306/1261 [06:12<22:38,  1.42s/it]

 24%|██▍       | 307/1261 [06:13<21:32,  1.35s/it]

 24%|██▍       | 308/1261 [06:15<22:42,  1.43s/it]

 25%|██▍       | 309/1261 [06:16<21:56,  1.38s/it]

 25%|██▍       | 310/1261 [06:17<22:18,  1.41s/it]

 25%|██▍       | 311/1261 [06:19<22:33,  1.42s/it]

 25%|██▍       | 312/1261 [06:20<22:20,  1.41s/it]

 25%|██▍       | 313/1261 [06:21<22:04,  1.40s/it]

 25%|██▍       | 314/1261 [06:24<27:28,  1.74s/it]

 25%|██▍       | 315/1261 [06:25<26:05,  1.65s/it]

 25%|██▌       | 316/1261 [06:27<26:33,  1.69s/it]

 25%|██▌       | 317/1261 [06:29<25:48,  1.64s/it]

 25%|██▌       | 318/1261 [06:30<24:27,  1.56s/it]

 25%|██▌       | 319/1261 [06:32<23:49,  1.52s/it]

 25%|██▌       | 320/1261 [06:33<23:39,  1.51s/it]

 25%|██▌       | 321/1261 [06:34<22:50,  1.46s/it]

 26%|██▌       | 322/1261 [06:36<22:44,  1.45s/it]

 26%|██▌       | 323/1261 [06:37<21:30,  1.38s/it]

 26%|██▌       | 324/1261 [06:38<21:14,  1.36s/it]

 26%|██▌       | 325/1261 [06:40<20:30,  1.31s/it]

 26%|██▌       | 326/1261 [06:41<20:32,  1.32s/it]

 26%|██▌       | 327/1261 [06:42<20:01,  1.29s/it]

 26%|██▌       | 328/1261 [06:43<20:03,  1.29s/it]

 26%|██▌       | 329/1261 [06:45<20:00,  1.29s/it]

 26%|██▌       | 330/1261 [06:46<22:05,  1.42s/it]

 26%|██▌       | 331/1261 [06:48<21:26,  1.38s/it]

 26%|██▋       | 332/1261 [06:49<21:41,  1.40s/it]

 26%|██▋       | 333/1261 [06:50<21:01,  1.36s/it]

 26%|██▋       | 334/1261 [06:52<20:21,  1.32s/it]

 27%|██▋       | 335/1261 [06:53<19:31,  1.26s/it]

 27%|██▋       | 336/1261 [06:54<19:16,  1.25s/it]

 27%|██▋       | 337/1261 [06:55<18:54,  1.23s/it]

 27%|██▋       | 338/1261 [06:56<18:39,  1.21s/it]

 27%|██▋       | 339/1261 [06:58<18:41,  1.22s/it]

 27%|██▋       | 340/1261 [06:59<19:42,  1.28s/it]

 27%|██▋       | 341/1261 [07:00<19:36,  1.28s/it]

 27%|██▋       | 342/1261 [07:02<19:34,  1.28s/it]

 27%|██▋       | 343/1261 [07:03<19:27,  1.27s/it]

 27%|██▋       | 344/1261 [07:04<18:52,  1.24s/it]

 27%|██▋       | 345/1261 [07:06<20:42,  1.36s/it]

 27%|██▋       | 346/1261 [07:07<20:47,  1.36s/it]

 28%|██▊       | 347/1261 [07:08<20:16,  1.33s/it]

 28%|██▊       | 348/1261 [07:10<20:27,  1.34s/it]

 28%|██▊       | 349/1261 [07:11<20:20,  1.34s/it]

 28%|██▊       | 350/1261 [07:12<20:50,  1.37s/it]

 28%|██▊       | 351/1261 [07:14<20:12,  1.33s/it]

 28%|██▊       | 352/1261 [07:15<21:05,  1.39s/it]

 28%|██▊       | 353/1261 [07:16<20:24,  1.35s/it]

 28%|██▊       | 354/1261 [07:18<20:24,  1.35s/it]

 28%|██▊       | 355/1261 [07:20<22:22,  1.48s/it]

 28%|██▊       | 356/1261 [07:22<26:37,  1.77s/it]

 28%|██▊       | 357/1261 [07:24<28:54,  1.92s/it]

 28%|██▊       | 358/1261 [07:26<29:47,  1.98s/it]

 28%|██▊       | 359/1261 [07:28<27:31,  1.83s/it]

 29%|██▊       | 360/1261 [07:30<27:00,  1.80s/it]

 29%|██▊       | 361/1261 [07:31<24:34,  1.64s/it]

 29%|██▊       | 362/1261 [07:32<23:02,  1.54s/it]

 29%|██▉       | 363/1261 [07:34<22:17,  1.49s/it]

 29%|██▉       | 364/1261 [07:35<21:30,  1.44s/it]

 29%|██▉       | 365/1261 [07:36<20:05,  1.35s/it]

 29%|██▉       | 366/1261 [07:37<19:30,  1.31s/it]

 29%|██▉       | 367/1261 [07:38<19:22,  1.30s/it]

 29%|██▉       | 368/1261 [07:40<19:14,  1.29s/it]

 29%|██▉       | 369/1261 [07:41<18:59,  1.28s/it]

 29%|██▉       | 370/1261 [07:43<22:21,  1.51s/it]

 29%|██▉       | 371/1261 [07:45<24:14,  1.63s/it]

 30%|██▉       | 372/1261 [07:46<22:54,  1.55s/it]

 30%|██▉       | 373/1261 [07:48<21:28,  1.45s/it]

 30%|██▉       | 374/1261 [07:49<21:57,  1.49s/it]

 30%|██▉       | 375/1261 [07:50<21:28,  1.45s/it]

 30%|██▉       | 376/1261 [07:52<21:37,  1.47s/it]

 30%|██▉       | 377/1261 [07:53<21:07,  1.43s/it]

 30%|██▉       | 378/1261 [07:55<20:27,  1.39s/it]

 30%|███       | 379/1261 [07:56<19:36,  1.33s/it]

 30%|███       | 380/1261 [07:57<19:13,  1.31s/it]

 30%|███       | 381/1261 [07:58<19:03,  1.30s/it]

 30%|███       | 382/1261 [08:00<18:41,  1.28s/it]

 30%|███       | 383/1261 [08:01<18:00,  1.23s/it]

 30%|███       | 384/1261 [08:02<17:59,  1.23s/it]

 31%|███       | 385/1261 [08:03<18:06,  1.24s/it]

 31%|███       | 386/1261 [08:05<18:32,  1.27s/it]

 31%|███       | 387/1261 [08:06<17:46,  1.22s/it]

 31%|███       | 388/1261 [08:07<18:01,  1.24s/it]

 31%|███       | 389/1261 [08:08<17:14,  1.19s/it]

 31%|███       | 390/1261 [08:09<17:05,  1.18s/it]

 31%|███       | 391/1261 [08:10<17:18,  1.19s/it]

 31%|███       | 392/1261 [08:12<17:47,  1.23s/it]

 31%|███       | 393/1261 [08:13<17:20,  1.20s/it]

 31%|███       | 394/1261 [08:14<17:15,  1.19s/it]

 31%|███▏      | 395/1261 [08:15<17:16,  1.20s/it]

 31%|███▏      | 396/1261 [08:16<16:58,  1.18s/it]

 31%|███▏      | 397/1261 [08:18<17:32,  1.22s/it]

 32%|███▏      | 398/1261 [08:19<16:59,  1.18s/it]

 32%|███▏      | 399/1261 [08:20<17:31,  1.22s/it]

 32%|███▏      | 400/1261 [08:21<18:25,  1.28s/it]

 32%|███▏      | 401/1261 [08:23<17:49,  1.24s/it]

 32%|███▏      | 402/1261 [08:24<17:41,  1.24s/it]

 32%|███▏      | 403/1261 [08:25<17:38,  1.23s/it]

 32%|███▏      | 404/1261 [08:26<18:05,  1.27s/it]

 32%|███▏      | 405/1261 [08:29<21:44,  1.52s/it]

 32%|███▏      | 406/1261 [08:30<23:21,  1.64s/it]

 32%|███▏      | 407/1261 [08:32<21:02,  1.48s/it]

 32%|███▏      | 408/1261 [08:33<20:14,  1.42s/it]

 32%|███▏      | 409/1261 [08:34<18:39,  1.31s/it]

 33%|███▎      | 410/1261 [08:35<18:07,  1.28s/it]

 33%|███▎      | 411/1261 [08:36<17:34,  1.24s/it]

 33%|███▎      | 412/1261 [08:37<17:16,  1.22s/it]

 33%|███▎      | 413/1261 [08:39<16:44,  1.18s/it]

 33%|███▎      | 414/1261 [08:40<16:25,  1.16s/it]

 33%|███▎      | 415/1261 [08:41<15:53,  1.13s/it]

 33%|███▎      | 416/1261 [08:42<15:51,  1.13s/it]

 33%|███▎      | 417/1261 [08:43<15:28,  1.10s/it]

 33%|███▎      | 418/1261 [08:44<15:41,  1.12s/it]

 33%|███▎      | 419/1261 [08:45<15:37,  1.11s/it]

 33%|███▎      | 420/1261 [08:46<15:56,  1.14s/it]

 33%|███▎      | 421/1261 [08:47<15:43,  1.12s/it]

 33%|███▎      | 422/1261 [08:48<15:35,  1.11s/it]

 34%|███▎      | 423/1261 [08:50<15:16,  1.09s/it]

 34%|███▎      | 424/1261 [08:51<15:36,  1.12s/it]

 34%|███▎      | 425/1261 [08:52<15:37,  1.12s/it]

 34%|███▍      | 426/1261 [08:53<15:36,  1.12s/it]

 34%|███▍      | 427/1261 [08:54<15:08,  1.09s/it]

 34%|███▍      | 428/1261 [08:55<15:26,  1.11s/it]

 34%|███▍      | 429/1261 [08:56<15:18,  1.10s/it]

 34%|███▍      | 430/1261 [08:57<15:09,  1.09s/it]

 34%|███▍      | 431/1261 [08:58<14:46,  1.07s/it]

 34%|███▍      | 432/1261 [08:59<14:59,  1.09s/it]

 34%|███▍      | 433/1261 [09:01<15:01,  1.09s/it]

 34%|███▍      | 434/1261 [09:02<15:10,  1.10s/it]

 34%|███▍      | 435/1261 [09:03<15:11,  1.10s/it]

 35%|███▍      | 436/1261 [09:04<15:15,  1.11s/it]

 35%|███▍      | 437/1261 [09:05<14:54,  1.09s/it]

 35%|███▍      | 438/1261 [09:06<15:07,  1.10s/it]

 35%|███▍      | 439/1261 [09:07<14:55,  1.09s/it]

 35%|███▍      | 440/1261 [09:08<15:52,  1.16s/it]

 35%|███▍      | 441/1261 [09:10<16:03,  1.18s/it]

 35%|███▌      | 442/1261 [09:11<17:00,  1.25s/it]

 35%|███▌      | 443/1261 [09:12<16:55,  1.24s/it]

 35%|███▌      | 444/1261 [09:14<17:17,  1.27s/it]

 35%|███▌      | 445/1261 [09:15<16:44,  1.23s/it]

 35%|███▌      | 446/1261 [09:17<19:54,  1.47s/it]

 35%|███▌      | 447/1261 [09:18<20:47,  1.53s/it]

 36%|███▌      | 448/1261 [09:20<19:03,  1.41s/it]

 36%|███▌      | 449/1261 [09:21<17:37,  1.30s/it]

 36%|███▌      | 450/1261 [09:22<17:01,  1.26s/it]

 36%|███▌      | 451/1261 [09:23<16:39,  1.23s/it]

 36%|███▌      | 452/1261 [09:24<16:29,  1.22s/it]

 36%|███▌      | 453/1261 [09:25<15:53,  1.18s/it]

 36%|███▌      | 454/1261 [09:26<15:35,  1.16s/it]

 36%|███▌      | 455/1261 [09:27<15:20,  1.14s/it]

 36%|███▌      | 456/1261 [09:29<15:01,  1.12s/it]

 36%|███▌      | 457/1261 [09:30<14:43,  1.10s/it]

 36%|███▋      | 458/1261 [09:31<14:58,  1.12s/it]

 36%|███▋      | 459/1261 [09:32<14:47,  1.11s/it]

 36%|███▋      | 460/1261 [09:33<14:23,  1.08s/it]

 37%|███▋      | 461/1261 [09:34<14:22,  1.08s/it]

 37%|███▋      | 462/1261 [09:35<14:33,  1.09s/it]

 37%|███▋      | 463/1261 [09:36<14:00,  1.05s/it]

 37%|███▋      | 464/1261 [09:37<14:17,  1.08s/it]

 37%|███▋      | 465/1261 [09:38<14:14,  1.07s/it]

 37%|███▋      | 466/1261 [09:39<14:02,  1.06s/it]

 37%|███▋      | 467/1261 [09:40<14:11,  1.07s/it]

 37%|███▋      | 468/1261 [09:41<14:17,  1.08s/it]

 37%|███▋      | 469/1261 [09:42<14:06,  1.07s/it]

 37%|███▋      | 470/1261 [09:44<14:09,  1.07s/it]

 37%|███▋      | 471/1261 [09:45<13:59,  1.06s/it]

 37%|███▋      | 472/1261 [09:46<14:04,  1.07s/it]

 38%|███▊      | 473/1261 [09:47<14:09,  1.08s/it]

 38%|███▊      | 474/1261 [09:48<14:17,  1.09s/it]

 38%|███▊      | 475/1261 [09:49<13:51,  1.06s/it]

 38%|███▊      | 476/1261 [09:50<14:04,  1.08s/it]

 38%|███▊      | 477/1261 [09:51<13:51,  1.06s/it]

 38%|███▊      | 478/1261 [09:52<13:50,  1.06s/it]

 38%|███▊      | 479/1261 [09:53<13:41,  1.05s/it]

 38%|███▊      | 480/1261 [09:54<13:52,  1.07s/it]

 38%|███▊      | 481/1261 [09:55<13:38,  1.05s/it]

 38%|███▊      | 482/1261 [09:56<13:48,  1.06s/it]

 38%|███▊      | 483/1261 [09:57<13:32,  1.04s/it]

 38%|███▊      | 484/1261 [09:58<13:43,  1.06s/it]

 38%|███▊      | 485/1261 [09:59<13:45,  1.06s/it]

 39%|███▊      | 486/1261 [10:01<13:55,  1.08s/it]

 39%|███▊      | 487/1261 [10:02<13:54,  1.08s/it]

 39%|███▊      | 488/1261 [10:03<13:59,  1.09s/it]

 39%|███▉      | 489/1261 [10:04<13:44,  1.07s/it]

 39%|███▉      | 490/1261 [10:05<13:45,  1.07s/it]

 39%|███▉      | 491/1261 [10:06<13:40,  1.07s/it]

 39%|███▉      | 492/1261 [10:07<13:35,  1.06s/it]

 39%|███▉      | 493/1261 [10:08<13:31,  1.06s/it]

 39%|███▉      | 494/1261 [10:09<13:40,  1.07s/it]

 39%|███▉      | 495/1261 [10:10<13:46,  1.08s/it]

 39%|███▉      | 496/1261 [10:11<14:16,  1.12s/it]

 39%|███▉      | 497/1261 [10:13<14:03,  1.10s/it]

 39%|███▉      | 498/1261 [10:14<14:04,  1.11s/it]

 40%|███▉      | 499/1261 [10:15<13:38,  1.07s/it]

 40%|███▉      | 500/1261 [10:16<13:40,  1.08s/it]

 40%|███▉      | 501/1261 [10:17<13:18,  1.05s/it]

 40%|███▉      | 502/1261 [10:18<13:14,  1.05s/it]

 40%|███▉      | 503/1261 [10:19<12:58,  1.03s/it]

 40%|███▉      | 504/1261 [10:20<13:24,  1.06s/it]

 40%|████      | 505/1261 [10:21<13:38,  1.08s/it]

 40%|████      | 506/1261 [10:22<13:59,  1.11s/it]

 40%|████      | 507/1261 [10:23<13:57,  1.11s/it]

 40%|████      | 508/1261 [10:24<14:16,  1.14s/it]

 40%|████      | 509/1261 [10:26<14:06,  1.13s/it]

 40%|████      | 510/1261 [10:27<14:09,  1.13s/it]

 41%|████      | 511/1261 [10:28<14:07,  1.13s/it]

 41%|████      | 512/1261 [10:29<14:20,  1.15s/it]

 41%|████      | 513/1261 [10:30<14:12,  1.14s/it]

 41%|████      | 514/1261 [10:31<14:28,  1.16s/it]

 41%|████      | 515/1261 [10:32<14:16,  1.15s/it]

 41%|████      | 516/1261 [10:34<14:23,  1.16s/it]

 41%|████      | 517/1261 [10:35<15:19,  1.24s/it]

 41%|████      | 518/1261 [10:36<15:18,  1.24s/it]

 41%|████      | 519/1261 [10:37<14:51,  1.20s/it]

 41%|████      | 520/1261 [10:39<16:01,  1.30s/it]

 41%|████▏     | 521/1261 [10:41<17:29,  1.42s/it]

 41%|████▏     | 522/1261 [10:42<17:06,  1.39s/it]

 41%|████▏     | 523/1261 [10:43<16:08,  1.31s/it]

 42%|████▏     | 524/1261 [10:44<15:41,  1.28s/it]

 42%|████▏     | 525/1261 [10:45<14:52,  1.21s/it]

 42%|████▏     | 526/1261 [10:47<14:57,  1.22s/it]

 42%|████▏     | 527/1261 [10:48<14:46,  1.21s/it]

 42%|████▏     | 528/1261 [10:49<14:42,  1.20s/it]

 42%|████▏     | 529/1261 [10:50<14:26,  1.18s/it]

 42%|████▏     | 530/1261 [10:51<14:32,  1.19s/it]

 42%|████▏     | 531/1261 [10:52<14:14,  1.17s/it]

 42%|████▏     | 532/1261 [10:54<14:04,  1.16s/it]

 42%|████▏     | 533/1261 [10:55<14:08,  1.17s/it]

 42%|████▏     | 534/1261 [10:56<14:05,  1.16s/it]

 42%|████▏     | 535/1261 [10:57<14:08,  1.17s/it]

 43%|████▎     | 536/1261 [10:58<14:04,  1.17s/it]

 43%|████▎     | 537/1261 [10:59<13:52,  1.15s/it]

 43%|████▎     | 538/1261 [11:01<13:47,  1.14s/it]

 43%|████▎     | 539/1261 [11:02<13:35,  1.13s/it]

 43%|████▎     | 540/1261 [11:03<13:40,  1.14s/it]

 43%|████▎     | 541/1261 [11:04<13:29,  1.12s/it]

 43%|████▎     | 542/1261 [11:05<13:27,  1.12s/it]

 43%|████▎     | 543/1261 [11:06<13:36,  1.14s/it]

 43%|████▎     | 544/1261 [11:07<13:41,  1.15s/it]

 43%|████▎     | 545/1261 [11:09<14:13,  1.19s/it]

 43%|████▎     | 546/1261 [11:10<15:25,  1.29s/it]

 43%|████▎     | 547/1261 [11:11<14:47,  1.24s/it]

 43%|████▎     | 548/1261 [11:13<15:08,  1.27s/it]

 44%|████▎     | 549/1261 [11:14<14:52,  1.25s/it]

 44%|████▎     | 550/1261 [11:15<14:54,  1.26s/it]

 44%|████▎     | 551/1261 [11:16<14:16,  1.21s/it]

 44%|████▍     | 552/1261 [11:17<14:03,  1.19s/it]

 44%|████▍     | 553/1261 [11:18<13:40,  1.16s/it]

 44%|████▍     | 554/1261 [11:20<13:39,  1.16s/it]

 44%|████▍     | 555/1261 [11:21<13:33,  1.15s/it]

 44%|████▍     | 556/1261 [11:22<13:48,  1.18s/it]

 44%|████▍     | 557/1261 [11:23<13:32,  1.15s/it]

 44%|████▍     | 558/1261 [11:24<13:35,  1.16s/it]

 44%|████▍     | 559/1261 [11:25<13:51,  1.19s/it]

 44%|████▍     | 560/1261 [11:27<14:21,  1.23s/it]

 44%|████▍     | 561/1261 [11:28<14:36,  1.25s/it]

 45%|████▍     | 562/1261 [11:29<14:31,  1.25s/it]

 45%|████▍     | 563/1261 [11:31<14:15,  1.23s/it]

 45%|████▍     | 564/1261 [11:32<13:52,  1.19s/it]

 45%|████▍     | 565/1261 [11:33<13:29,  1.16s/it]

 45%|████▍     | 566/1261 [11:34<13:38,  1.18s/it]

 45%|████▍     | 567/1261 [11:35<13:12,  1.14s/it]

 45%|████▌     | 568/1261 [11:36<13:25,  1.16s/it]

 45%|████▌     | 569/1261 [11:37<13:09,  1.14s/it]

 45%|████▌     | 570/1261 [11:38<13:04,  1.14s/it]

 45%|████▌     | 571/1261 [11:40<13:02,  1.13s/it]

 45%|████▌     | 572/1261 [11:41<13:07,  1.14s/it]

 45%|████▌     | 573/1261 [11:42<13:03,  1.14s/it]

 46%|████▌     | 574/1261 [11:43<12:57,  1.13s/it]

 46%|████▌     | 575/1261 [11:44<12:45,  1.12s/it]

 46%|████▌     | 576/1261 [11:45<12:56,  1.13s/it]

 46%|████▌     | 577/1261 [11:46<12:45,  1.12s/it]

 46%|████▌     | 578/1261 [11:47<12:45,  1.12s/it]

 46%|████▌     | 579/1261 [11:49<12:48,  1.13s/it]

 46%|████▌     | 580/1261 [11:50<12:54,  1.14s/it]

 46%|████▌     | 581/1261 [11:51<12:48,  1.13s/it]

 46%|████▌     | 582/1261 [11:52<12:58,  1.15s/it]

 46%|████▌     | 583/1261 [11:53<12:59,  1.15s/it]

 46%|████▋     | 584/1261 [11:54<13:18,  1.18s/it]

 46%|████▋     | 585/1261 [11:56<14:00,  1.24s/it]

 46%|████▋     | 586/1261 [11:57<14:32,  1.29s/it]

 47%|████▋     | 587/1261 [11:58<14:10,  1.26s/it]

 47%|████▋     | 588/1261 [12:00<16:08,  1.44s/it]

 47%|████▋     | 589/1261 [12:02<15:49,  1.41s/it]

 47%|████▋     | 590/1261 [12:03<15:48,  1.41s/it]

 47%|████▋     | 591/1261 [12:04<14:57,  1.34s/it]

 47%|████▋     | 592/1261 [12:06<14:53,  1.34s/it]

 47%|████▋     | 593/1261 [12:07<14:26,  1.30s/it]

 47%|████▋     | 594/1261 [12:08<14:00,  1.26s/it]

 47%|████▋     | 595/1261 [12:09<13:18,  1.20s/it]

 47%|████▋     | 596/1261 [12:10<14:20,  1.29s/it]

 47%|████▋     | 597/1261 [12:12<14:38,  1.32s/it]

 47%|████▋     | 598/1261 [12:14<15:59,  1.45s/it]

 48%|████▊     | 599/1261 [12:15<15:37,  1.42s/it]

 48%|████▊     | 600/1261 [12:16<15:27,  1.40s/it]

 48%|████▊     | 601/1261 [12:17<14:25,  1.31s/it]

 48%|████▊     | 602/1261 [12:19<13:56,  1.27s/it]

 48%|████▊     | 603/1261 [12:20<13:34,  1.24s/it]

 48%|████▊     | 604/1261 [12:22<15:52,  1.45s/it]

 48%|████▊     | 605/1261 [12:23<15:03,  1.38s/it]

 48%|████▊     | 606/1261 [12:24<14:22,  1.32s/it]

 48%|████▊     | 607/1261 [12:25<13:31,  1.24s/it]

 48%|████▊     | 608/1261 [12:26<13:04,  1.20s/it]

 48%|████▊     | 609/1261 [12:27<13:07,  1.21s/it]

 48%|████▊     | 610/1261 [12:29<13:42,  1.26s/it]

 48%|████▊     | 611/1261 [12:30<13:42,  1.27s/it]

 49%|████▊     | 612/1261 [12:32<14:07,  1.31s/it]

 49%|████▊     | 613/1261 [12:33<13:47,  1.28s/it]

 49%|████▊     | 614/1261 [12:34<13:27,  1.25s/it]

 49%|████▉     | 615/1261 [12:35<14:16,  1.33s/it]

 49%|████▉     | 616/1261 [12:37<13:57,  1.30s/it]

 49%|████▉     | 617/1261 [12:38<13:26,  1.25s/it]

 49%|████▉     | 618/1261 [12:39<13:01,  1.22s/it]

 49%|████▉     | 619/1261 [12:40<12:46,  1.19s/it]

 49%|████▉     | 620/1261 [12:41<12:38,  1.18s/it]

 49%|████▉     | 621/1261 [12:42<12:21,  1.16s/it]

 49%|████▉     | 622/1261 [12:44<12:42,  1.19s/it]

 49%|████▉     | 623/1261 [12:45<12:35,  1.18s/it]

 49%|████▉     | 624/1261 [12:46<12:20,  1.16s/it]

 50%|████▉     | 625/1261 [12:47<12:17,  1.16s/it]

 50%|████▉     | 626/1261 [12:48<12:19,  1.16s/it]

 50%|████▉     | 627/1261 [12:50<12:58,  1.23s/it]

 50%|████▉     | 628/1261 [12:51<13:10,  1.25s/it]

 50%|████▉     | 629/1261 [12:52<13:14,  1.26s/it]

 50%|████▉     | 630/1261 [12:53<12:57,  1.23s/it]

 50%|█████     | 631/1261 [12:55<12:44,  1.21s/it]

 50%|█████     | 632/1261 [12:56<12:37,  1.20s/it]

 50%|█████     | 633/1261 [12:57<12:31,  1.20s/it]

 50%|█████     | 634/1261 [12:58<12:54,  1.23s/it]

 50%|█████     | 635/1261 [12:59<12:55,  1.24s/it]

 50%|█████     | 636/1261 [13:01<12:39,  1.22s/it]

 51%|█████     | 637/1261 [13:02<12:11,  1.17s/it]

 51%|█████     | 638/1261 [13:03<12:30,  1.20s/it]

 51%|█████     | 639/1261 [13:04<12:11,  1.18s/it]

 51%|█████     | 640/1261 [13:05<12:27,  1.20s/it]

 51%|█████     | 641/1261 [13:06<12:00,  1.16s/it]

 51%|█████     | 642/1261 [13:07<11:42,  1.13s/it]

 51%|█████     | 643/1261 [13:09<11:43,  1.14s/it]

 51%|█████     | 644/1261 [13:10<11:30,  1.12s/it]

 51%|█████     | 645/1261 [13:11<11:47,  1.15s/it]

 51%|█████     | 646/1261 [13:12<12:07,  1.18s/it]

 51%|█████▏    | 647/1261 [13:13<11:58,  1.17s/it]

 51%|█████▏    | 648/1261 [13:15<12:21,  1.21s/it]

 51%|█████▏    | 649/1261 [13:16<11:59,  1.18s/it]

 52%|█████▏    | 650/1261 [13:17<12:11,  1.20s/it]

 52%|█████▏    | 651/1261 [13:18<11:55,  1.17s/it]

 52%|█████▏    | 652/1261 [13:19<12:05,  1.19s/it]

 52%|█████▏    | 653/1261 [13:20<11:37,  1.15s/it]

 52%|█████▏    | 654/1261 [13:22<11:58,  1.18s/it]

 52%|█████▏    | 655/1261 [13:23<11:57,  1.18s/it]

 52%|█████▏    | 656/1261 [13:24<12:09,  1.21s/it]

 52%|█████▏    | 657/1261 [13:25<12:02,  1.20s/it]

 52%|█████▏    | 658/1261 [13:26<11:54,  1.18s/it]

 52%|█████▏    | 659/1261 [13:28<11:45,  1.17s/it]

 52%|█████▏    | 660/1261 [13:29<11:38,  1.16s/it]

 52%|█████▏    | 661/1261 [13:30<11:25,  1.14s/it]

 52%|█████▏    | 662/1261 [13:31<11:32,  1.16s/it]

 53%|█████▎    | 663/1261 [13:32<11:19,  1.14s/it]

 53%|█████▎    | 664/1261 [13:33<11:10,  1.12s/it]

 53%|█████▎    | 665/1261 [13:34<11:12,  1.13s/it]

 53%|█████▎    | 666/1261 [13:35<11:18,  1.14s/it]

 53%|█████▎    | 667/1261 [13:37<11:04,  1.12s/it]

 53%|█████▎    | 668/1261 [13:38<11:08,  1.13s/it]

 53%|█████▎    | 669/1261 [13:39<10:58,  1.11s/it]

 53%|█████▎    | 670/1261 [13:40<10:54,  1.11s/it]

 53%|█████▎    | 671/1261 [13:41<10:48,  1.10s/it]

 53%|█████▎    | 672/1261 [13:42<10:54,  1.11s/it]

 53%|█████▎    | 673/1261 [13:43<10:50,  1.11s/it]

 53%|█████▎    | 674/1261 [13:44<10:51,  1.11s/it]

 54%|█████▎    | 675/1261 [13:45<10:38,  1.09s/it]

 54%|█████▎    | 676/1261 [13:46<10:25,  1.07s/it]

 54%|█████▎    | 677/1261 [13:47<10:30,  1.08s/it]

 54%|█████▍    | 678/1261 [13:49<10:36,  1.09s/it]

 54%|█████▍    | 679/1261 [13:50<10:18,  1.06s/it]

 54%|█████▍    | 680/1261 [13:51<10:30,  1.09s/it]

 54%|█████▍    | 681/1261 [13:52<10:04,  1.04s/it]

 54%|█████▍    | 682/1261 [13:53<10:17,  1.07s/it]

 54%|█████▍    | 683/1261 [13:54<10:09,  1.05s/it]

 54%|█████▍    | 684/1261 [13:55<10:07,  1.05s/it]

 54%|█████▍    | 685/1261 [13:56<09:57,  1.04s/it]

 54%|█████▍    | 686/1261 [13:57<10:14,  1.07s/it]

 54%|█████▍    | 687/1261 [13:58<10:05,  1.06s/it]

 55%|█████▍    | 688/1261 [13:59<10:26,  1.09s/it]

 55%|█████▍    | 689/1261 [14:00<10:17,  1.08s/it]

 55%|█████▍    | 690/1261 [14:01<10:30,  1.10s/it]

 55%|█████▍    | 691/1261 [14:02<10:24,  1.09s/it]

 55%|█████▍    | 692/1261 [14:04<10:11,  1.08s/it]

 55%|█████▍    | 693/1261 [14:05<10:12,  1.08s/it]

 55%|█████▌    | 694/1261 [14:06<10:15,  1.09s/it]

 55%|█████▌    | 695/1261 [14:07<10:04,  1.07s/it]

 55%|█████▌    | 696/1261 [14:08<10:06,  1.07s/it]

 55%|█████▌    | 697/1261 [14:09<09:59,  1.06s/it]

 55%|█████▌    | 698/1261 [14:10<10:21,  1.10s/it]

 55%|█████▌    | 699/1261 [14:12<11:49,  1.26s/it]

 56%|█████▌    | 700/1261 [14:13<11:39,  1.25s/it]

 56%|█████▌    | 701/1261 [14:14<11:13,  1.20s/it]

 56%|█████▌    | 702/1261 [14:15<10:56,  1.17s/it]

 56%|█████▌    | 703/1261 [14:16<10:40,  1.15s/it]

 56%|█████▌    | 704/1261 [14:17<10:38,  1.15s/it]

 56%|█████▌    | 705/1261 [14:18<10:14,  1.11s/it]

 56%|█████▌    | 706/1261 [14:20<10:22,  1.12s/it]

 56%|█████▌    | 707/1261 [14:21<10:20,  1.12s/it]

 56%|█████▌    | 708/1261 [14:22<10:29,  1.14s/it]

 56%|█████▌    | 709/1261 [14:23<10:20,  1.12s/it]

 56%|█████▋    | 710/1261 [14:24<10:46,  1.17s/it]

 56%|█████▋    | 711/1261 [14:25<10:31,  1.15s/it]

 56%|█████▋    | 712/1261 [14:26<10:34,  1.16s/it]

 57%|█████▋    | 713/1261 [14:28<10:27,  1.14s/it]

 57%|█████▋    | 714/1261 [14:29<10:30,  1.15s/it]

 57%|█████▋    | 715/1261 [14:30<10:22,  1.14s/it]

 57%|█████▋    | 716/1261 [14:31<10:39,  1.17s/it]

 57%|█████▋    | 717/1261 [14:32<10:39,  1.17s/it]

 57%|█████▋    | 718/1261 [14:33<10:38,  1.18s/it]

 57%|█████▋    | 719/1261 [14:35<10:36,  1.17s/it]

 57%|█████▋    | 720/1261 [14:36<10:51,  1.20s/it]

 57%|█████▋    | 721/1261 [14:37<10:36,  1.18s/it]

 57%|█████▋    | 722/1261 [14:38<10:42,  1.19s/it]

 57%|█████▋    | 723/1261 [14:39<10:41,  1.19s/it]

 57%|█████▋    | 724/1261 [14:41<10:41,  1.20s/it]

 57%|█████▋    | 725/1261 [14:42<10:37,  1.19s/it]

 58%|█████▊    | 726/1261 [14:43<11:23,  1.28s/it]

 58%|█████▊    | 727/1261 [14:44<10:59,  1.23s/it]

 58%|█████▊    | 728/1261 [14:46<11:17,  1.27s/it]

 58%|█████▊    | 729/1261 [14:47<11:06,  1.25s/it]

 58%|█████▊    | 730/1261 [14:48<10:44,  1.21s/it]

 58%|█████▊    | 731/1261 [14:49<10:45,  1.22s/it]

 58%|█████▊    | 732/1261 [14:51<10:51,  1.23s/it]

 58%|█████▊    | 733/1261 [14:52<10:28,  1.19s/it]

 58%|█████▊    | 734/1261 [14:53<10:45,  1.22s/it]

 58%|█████▊    | 735/1261 [14:54<10:43,  1.22s/it]

 58%|█████▊    | 736/1261 [14:56<10:52,  1.24s/it]

 58%|█████▊    | 737/1261 [14:57<10:31,  1.21s/it]

 59%|█████▊    | 738/1261 [14:58<10:32,  1.21s/it]

 59%|█████▊    | 739/1261 [14:59<10:38,  1.22s/it]

 59%|█████▊    | 740/1261 [15:00<10:29,  1.21s/it]

 59%|█████▉    | 741/1261 [15:02<10:35,  1.22s/it]

 59%|█████▉    | 742/1261 [15:03<10:37,  1.23s/it]

 59%|█████▉    | 743/1261 [15:04<10:22,  1.20s/it]

 59%|█████▉    | 744/1261 [15:05<10:17,  1.19s/it]

 59%|█████▉    | 745/1261 [15:06<10:16,  1.20s/it]

 59%|█████▉    | 746/1261 [15:08<10:35,  1.23s/it]

 59%|█████▉    | 747/1261 [15:09<10:15,  1.20s/it]

 59%|█████▉    | 748/1261 [15:10<10:20,  1.21s/it]

 59%|█████▉    | 749/1261 [15:11<10:26,  1.22s/it]

 59%|█████▉    | 750/1261 [15:13<10:32,  1.24s/it]

 60%|█████▉    | 751/1261 [15:14<10:29,  1.23s/it]

 60%|█████▉    | 752/1261 [15:15<10:40,  1.26s/it]

 60%|█████▉    | 753/1261 [15:16<10:23,  1.23s/it]

 60%|█████▉    | 754/1261 [15:17<10:11,  1.21s/it]

 60%|█████▉    | 755/1261 [15:19<10:03,  1.19s/it]

 60%|█████▉    | 756/1261 [15:20<10:10,  1.21s/it]

 60%|██████    | 757/1261 [15:21<09:52,  1.18s/it]

 60%|██████    | 758/1261 [15:22<09:52,  1.18s/it]

 60%|██████    | 759/1261 [15:23<09:39,  1.15s/it]

 60%|██████    | 760/1261 [15:24<09:52,  1.18s/it]

 60%|██████    | 761/1261 [15:26<09:40,  1.16s/it]

 60%|██████    | 762/1261 [15:27<09:49,  1.18s/it]

 61%|██████    | 763/1261 [15:28<09:43,  1.17s/it]

 61%|██████    | 764/1261 [15:29<09:46,  1.18s/it]

 61%|██████    | 765/1261 [15:30<09:32,  1.15s/it]

 61%|██████    | 766/1261 [15:31<09:31,  1.15s/it]

 61%|██████    | 767/1261 [15:33<09:33,  1.16s/it]

 61%|██████    | 768/1261 [15:34<09:40,  1.18s/it]

 61%|██████    | 769/1261 [15:35<09:38,  1.18s/it]

 61%|██████    | 770/1261 [15:36<09:37,  1.18s/it]

 61%|██████    | 771/1261 [15:37<09:29,  1.16s/it]

 61%|██████    | 772/1261 [15:38<09:27,  1.16s/it]

 61%|██████▏   | 773/1261 [15:39<09:21,  1.15s/it]

 61%|██████▏   | 774/1261 [15:41<09:18,  1.15s/it]

 61%|██████▏   | 775/1261 [15:42<09:19,  1.15s/it]

 62%|██████▏   | 776/1261 [15:43<09:24,  1.16s/it]

 62%|██████▏   | 777/1261 [15:44<09:14,  1.15s/it]

 62%|██████▏   | 778/1261 [15:45<09:35,  1.19s/it]

 62%|██████▏   | 779/1261 [15:47<09:54,  1.23s/it]

 62%|██████▏   | 780/1261 [15:49<11:38,  1.45s/it]

 62%|██████▏   | 781/1261 [15:50<10:52,  1.36s/it]

 62%|██████▏   | 782/1261 [15:51<11:01,  1.38s/it]

 62%|██████▏   | 783/1261 [15:52<10:22,  1.30s/it]

 62%|██████▏   | 784/1261 [15:54<10:14,  1.29s/it]

 62%|██████▏   | 785/1261 [15:55<10:07,  1.28s/it]

 62%|██████▏   | 786/1261 [15:56<09:48,  1.24s/it]

 62%|██████▏   | 787/1261 [15:57<09:32,  1.21s/it]

 62%|██████▏   | 788/1261 [15:58<09:23,  1.19s/it]

 63%|██████▎   | 789/1261 [16:00<09:22,  1.19s/it]

 63%|██████▎   | 790/1261 [16:01<09:33,  1.22s/it]

 63%|██████▎   | 791/1261 [16:02<09:34,  1.22s/it]

 63%|██████▎   | 792/1261 [16:03<09:35,  1.23s/it]

 63%|██████▎   | 793/1261 [16:05<09:42,  1.24s/it]

 63%|██████▎   | 794/1261 [16:06<09:36,  1.24s/it]

 63%|██████▎   | 795/1261 [16:07<09:21,  1.21s/it]

 63%|██████▎   | 796/1261 [16:08<09:19,  1.20s/it]

 63%|██████▎   | 797/1261 [16:09<09:09,  1.18s/it]

 63%|██████▎   | 798/1261 [16:10<09:19,  1.21s/it]

 63%|██████▎   | 799/1261 [16:12<09:10,  1.19s/it]

 63%|██████▎   | 800/1261 [16:13<09:14,  1.20s/it]

 64%|██████▎   | 801/1261 [16:14<09:00,  1.18s/it]

 64%|██████▎   | 802/1261 [16:15<09:12,  1.20s/it]

 64%|██████▎   | 803/1261 [16:16<09:09,  1.20s/it]

 64%|██████▍   | 804/1261 [16:18<09:11,  1.21s/it]

 64%|██████▍   | 805/1261 [16:19<09:11,  1.21s/it]

 64%|██████▍   | 806/1261 [16:20<09:20,  1.23s/it]

 64%|██████▍   | 807/1261 [16:21<09:14,  1.22s/it]

 64%|██████▍   | 808/1261 [16:23<09:21,  1.24s/it]

 64%|██████▍   | 809/1261 [16:24<09:10,  1.22s/it]

 64%|██████▍   | 810/1261 [16:25<09:31,  1.27s/it]

 64%|██████▍   | 811/1261 [16:26<09:19,  1.24s/it]

 64%|██████▍   | 812/1261 [16:28<09:41,  1.29s/it]

 64%|██████▍   | 813/1261 [16:29<09:38,  1.29s/it]

 65%|██████▍   | 814/1261 [16:30<09:29,  1.27s/it]

 65%|██████▍   | 815/1261 [16:32<09:29,  1.28s/it]

 65%|██████▍   | 816/1261 [16:33<09:26,  1.27s/it]

 65%|██████▍   | 817/1261 [16:34<09:02,  1.22s/it]

 65%|██████▍   | 818/1261 [16:35<09:21,  1.27s/it]

 65%|██████▍   | 819/1261 [16:37<09:09,  1.24s/it]

 65%|██████▌   | 820/1261 [16:38<09:08,  1.24s/it]

 65%|██████▌   | 821/1261 [16:39<09:04,  1.24s/it]

 65%|██████▌   | 822/1261 [16:40<09:04,  1.24s/it]

 65%|██████▌   | 823/1261 [16:42<09:07,  1.25s/it]

 65%|██████▌   | 824/1261 [16:43<09:19,  1.28s/it]

 65%|██████▌   | 825/1261 [16:44<09:14,  1.27s/it]

 66%|██████▌   | 826/1261 [16:45<09:14,  1.28s/it]

 66%|██████▌   | 827/1261 [16:47<08:52,  1.23s/it]

 66%|██████▌   | 828/1261 [16:48<08:55,  1.24s/it]

 66%|██████▌   | 829/1261 [16:49<08:41,  1.21s/it]

 66%|██████▌   | 830/1261 [16:50<08:59,  1.25s/it]

 66%|██████▌   | 831/1261 [16:51<08:49,  1.23s/it]

 66%|██████▌   | 832/1261 [16:53<09:15,  1.29s/it]

 66%|██████▌   | 833/1261 [16:54<09:15,  1.30s/it]

 66%|██████▌   | 834/1261 [16:56<09:17,  1.31s/it]

 66%|██████▌   | 835/1261 [16:57<09:04,  1.28s/it]

 66%|██████▋   | 836/1261 [16:58<08:53,  1.25s/it]

 66%|██████▋   | 837/1261 [16:59<08:31,  1.21s/it]

 66%|██████▋   | 838/1261 [17:00<08:42,  1.24s/it]

 67%|██████▋   | 839/1261 [17:02<08:40,  1.23s/it]

 67%|██████▋   | 840/1261 [17:03<08:46,  1.25s/it]

 67%|██████▋   | 841/1261 [17:04<08:26,  1.21s/it]

 67%|██████▋   | 842/1261 [17:05<08:42,  1.25s/it]

 67%|██████▋   | 843/1261 [17:07<08:43,  1.25s/it]

 67%|██████▋   | 844/1261 [17:08<08:59,  1.29s/it]

 67%|██████▋   | 845/1261 [17:09<08:41,  1.25s/it]

 67%|██████▋   | 846/1261 [17:11<09:25,  1.36s/it]

 67%|██████▋   | 847/1261 [17:12<08:54,  1.29s/it]

 67%|██████▋   | 848/1261 [17:13<08:43,  1.27s/it]

 67%|██████▋   | 849/1261 [17:14<08:30,  1.24s/it]

 67%|██████▋   | 850/1261 [17:16<08:40,  1.27s/it]

 67%|██████▋   | 851/1261 [17:17<08:43,  1.28s/it]

 68%|██████▊   | 852/1261 [17:18<08:44,  1.28s/it]

 68%|██████▊   | 853/1261 [17:19<08:25,  1.24s/it]

 68%|██████▊   | 854/1261 [17:21<08:57,  1.32s/it]

 68%|██████▊   | 855/1261 [17:23<09:53,  1.46s/it]

 68%|██████▊   | 856/1261 [17:24<09:23,  1.39s/it]

 68%|██████▊   | 857/1261 [17:25<09:05,  1.35s/it]

 68%|██████▊   | 858/1261 [17:26<08:52,  1.32s/it]

 68%|██████▊   | 859/1261 [17:28<08:37,  1.29s/it]

 68%|██████▊   | 860/1261 [17:29<08:37,  1.29s/it]

 68%|██████▊   | 861/1261 [17:30<08:23,  1.26s/it]

 68%|██████▊   | 862/1261 [17:31<08:26,  1.27s/it]

 68%|██████▊   | 863/1261 [17:33<08:19,  1.25s/it]

 69%|██████▊   | 864/1261 [17:34<08:19,  1.26s/it]

 69%|██████▊   | 865/1261 [17:35<08:07,  1.23s/it]

 69%|██████▊   | 866/1261 [17:36<08:00,  1.22s/it]

 69%|██████▉   | 867/1261 [17:37<07:41,  1.17s/it]

 69%|██████▉   | 868/1261 [17:38<07:44,  1.18s/it]

 69%|██████▉   | 869/1261 [17:40<07:29,  1.15s/it]

 69%|██████▉   | 870/1261 [17:41<07:23,  1.14s/it]

 69%|██████▉   | 871/1261 [17:42<07:16,  1.12s/it]

 69%|██████▉   | 872/1261 [17:43<07:15,  1.12s/it]

 69%|██████▉   | 873/1261 [17:44<07:02,  1.09s/it]

 69%|██████▉   | 874/1261 [17:45<07:10,  1.11s/it]

 69%|██████▉   | 875/1261 [17:46<07:02,  1.09s/it]

 69%|██████▉   | 876/1261 [17:47<07:02,  1.10s/it]

 70%|██████▉   | 877/1261 [17:48<06:51,  1.07s/it]

 70%|██████▉   | 878/1261 [17:49<07:00,  1.10s/it]

 70%|██████▉   | 879/1261 [17:50<06:55,  1.09s/it]

 70%|██████▉   | 880/1261 [17:51<06:55,  1.09s/it]

 70%|██████▉   | 881/1261 [17:53<06:58,  1.10s/it]

 70%|██████▉   | 882/1261 [17:54<06:59,  1.11s/it]

 70%|███████   | 883/1261 [17:55<06:53,  1.09s/it]

 70%|███████   | 884/1261 [17:56<06:52,  1.09s/it]

 70%|███████   | 885/1261 [17:57<06:47,  1.08s/it]

 70%|███████   | 886/1261 [17:58<06:55,  1.11s/it]

 70%|███████   | 887/1261 [17:59<06:44,  1.08s/it]

 70%|███████   | 888/1261 [18:00<06:48,  1.09s/it]

 70%|███████   | 889/1261 [18:01<06:41,  1.08s/it]

 71%|███████   | 890/1261 [18:02<06:39,  1.08s/it]

 71%|███████   | 891/1261 [18:03<06:43,  1.09s/it]

 71%|███████   | 892/1261 [18:05<06:53,  1.12s/it]

 71%|███████   | 893/1261 [18:06<06:51,  1.12s/it]

 71%|███████   | 894/1261 [18:07<06:57,  1.14s/it]

 71%|███████   | 895/1261 [18:08<06:49,  1.12s/it]

 71%|███████   | 896/1261 [18:09<06:46,  1.11s/it]

 71%|███████   | 897/1261 [18:10<06:43,  1.11s/it]

 71%|███████   | 898/1261 [18:11<06:48,  1.12s/it]

 71%|███████▏  | 899/1261 [18:12<06:41,  1.11s/it]

 71%|███████▏  | 900/1261 [18:14<06:41,  1.11s/it]

 71%|███████▏  | 901/1261 [18:15<06:39,  1.11s/it]

 72%|███████▏  | 902/1261 [18:16<06:42,  1.12s/it]

 72%|███████▏  | 903/1261 [18:17<06:27,  1.08s/it]

 72%|███████▏  | 904/1261 [18:18<06:30,  1.09s/it]

 72%|███████▏  | 905/1261 [18:19<06:25,  1.08s/it]

 72%|███████▏  | 906/1261 [18:20<06:29,  1.10s/it]

 72%|███████▏  | 907/1261 [18:21<06:26,  1.09s/it]

 72%|███████▏  | 908/1261 [18:22<06:25,  1.09s/it]

 72%|███████▏  | 909/1261 [18:23<06:19,  1.08s/it]

 72%|███████▏  | 910/1261 [18:25<06:25,  1.10s/it]

 72%|███████▏  | 911/1261 [18:26<06:17,  1.08s/it]

 72%|███████▏  | 912/1261 [18:27<06:24,  1.10s/it]

 72%|███████▏  | 913/1261 [18:28<06:22,  1.10s/it]

 72%|███████▏  | 914/1261 [18:29<06:20,  1.10s/it]

 73%|███████▎  | 915/1261 [18:30<06:20,  1.10s/it]

 73%|███████▎  | 916/1261 [18:31<06:19,  1.10s/it]

 73%|███████▎  | 917/1261 [18:32<06:18,  1.10s/it]

 73%|███████▎  | 918/1261 [18:33<06:19,  1.11s/it]

 73%|███████▎  | 919/1261 [18:34<06:16,  1.10s/it]

 73%|███████▎  | 920/1261 [18:36<06:22,  1.12s/it]

 73%|███████▎  | 921/1261 [18:37<06:20,  1.12s/it]

 73%|███████▎  | 922/1261 [18:38<06:19,  1.12s/it]

 73%|███████▎  | 923/1261 [18:39<06:12,  1.10s/it]

 73%|███████▎  | 924/1261 [18:40<06:17,  1.12s/it]

 73%|███████▎  | 925/1261 [18:41<06:08,  1.10s/it]

 73%|███████▎  | 926/1261 [18:42<06:11,  1.11s/it]

 74%|███████▎  | 927/1261 [18:43<06:07,  1.10s/it]

 74%|███████▎  | 928/1261 [18:44<06:12,  1.12s/it]

 74%|███████▎  | 929/1261 [18:46<06:08,  1.11s/it]

 74%|███████▍  | 930/1261 [18:47<06:10,  1.12s/it]

 74%|███████▍  | 931/1261 [18:48<06:07,  1.11s/it]

 74%|███████▍  | 932/1261 [18:49<06:04,  1.11s/it]

 74%|███████▍  | 933/1261 [18:50<06:05,  1.12s/it]

 74%|███████▍  | 934/1261 [18:51<06:05,  1.12s/it]

 74%|███████▍  | 935/1261 [18:52<05:55,  1.09s/it]

 74%|███████▍  | 936/1261 [18:53<06:01,  1.11s/it]

 74%|███████▍  | 937/1261 [18:54<05:55,  1.10s/it]

 74%|███████▍  | 938/1261 [18:56<06:00,  1.12s/it]

 74%|███████▍  | 939/1261 [18:57<05:57,  1.11s/it]

 75%|███████▍  | 940/1261 [18:58<05:57,  1.11s/it]

 75%|███████▍  | 941/1261 [18:59<05:52,  1.10s/it]

 75%|███████▍  | 942/1261 [19:00<05:56,  1.12s/it]

 75%|███████▍  | 943/1261 [19:01<05:56,  1.12s/it]

 75%|███████▍  | 944/1261 [19:02<05:50,  1.10s/it]

 75%|███████▍  | 945/1261 [19:03<05:50,  1.11s/it]

 75%|███████▌  | 946/1261 [19:04<05:50,  1.11s/it]

 75%|███████▌  | 947/1261 [19:06<05:45,  1.10s/it]

 75%|███████▌  | 948/1261 [19:07<05:46,  1.11s/it]

 75%|███████▌  | 949/1261 [19:08<05:45,  1.11s/it]

 75%|███████▌  | 950/1261 [19:09<05:45,  1.11s/it]

 75%|███████▌  | 951/1261 [19:10<05:46,  1.12s/it]

 75%|███████▌  | 952/1261 [19:11<05:59,  1.16s/it]

 76%|███████▌  | 953/1261 [19:13<06:06,  1.19s/it]

 76%|███████▌  | 954/1261 [19:14<06:00,  1.17s/it]

 76%|███████▌  | 955/1261 [19:15<06:01,  1.18s/it]

 76%|███████▌  | 956/1261 [19:16<06:12,  1.22s/it]

 76%|███████▌  | 957/1261 [19:17<06:03,  1.19s/it]

 76%|███████▌  | 958/1261 [19:18<06:00,  1.19s/it]

 76%|███████▌  | 959/1261 [19:20<06:01,  1.20s/it]

 76%|███████▌  | 960/1261 [19:21<06:00,  1.20s/it]

 76%|███████▌  | 961/1261 [19:22<05:52,  1.17s/it]

 76%|███████▋  | 962/1261 [19:23<05:59,  1.20s/it]

 76%|███████▋  | 963/1261 [19:24<05:57,  1.20s/it]

 76%|███████▋  | 964/1261 [19:26<06:04,  1.23s/it]

 77%|███████▋  | 965/1261 [19:27<06:00,  1.22s/it]

 77%|███████▋  | 966/1261 [19:28<05:54,  1.20s/it]

 77%|███████▋  | 967/1261 [19:29<05:51,  1.19s/it]

 77%|███████▋  | 968/1261 [19:31<05:55,  1.21s/it]

 77%|███████▋  | 969/1261 [19:32<05:51,  1.21s/it]

 77%|███████▋  | 970/1261 [19:33<05:47,  1.19s/it]

 77%|███████▋  | 971/1261 [19:34<05:46,  1.19s/it]

 77%|███████▋  | 972/1261 [19:35<05:55,  1.23s/it]

 77%|███████▋  | 973/1261 [19:37<05:54,  1.23s/it]

 77%|███████▋  | 974/1261 [19:38<05:53,  1.23s/it]

 77%|███████▋  | 975/1261 [19:39<05:43,  1.20s/it]

 77%|███████▋  | 976/1261 [19:40<05:39,  1.19s/it]

 77%|███████▋  | 977/1261 [19:41<05:39,  1.19s/it]

 78%|███████▊  | 978/1261 [19:42<05:30,  1.17s/it]

 78%|███████▊  | 979/1261 [19:44<05:28,  1.17s/it]

 78%|███████▊  | 980/1261 [19:45<05:25,  1.16s/it]

 78%|███████▊  | 981/1261 [19:46<05:16,  1.13s/it]

 78%|███████▊  | 982/1261 [19:47<05:15,  1.13s/it]

 78%|███████▊  | 983/1261 [19:48<05:15,  1.13s/it]

 78%|███████▊  | 984/1261 [19:49<05:22,  1.16s/it]

 78%|███████▊  | 985/1261 [19:51<05:37,  1.22s/it]

 78%|███████▊  | 986/1261 [19:52<05:48,  1.27s/it]

 78%|███████▊  | 987/1261 [19:54<06:38,  1.46s/it]

 78%|███████▊  | 988/1261 [19:57<08:12,  1.80s/it]

 78%|███████▊  | 989/1261 [19:58<07:24,  1.64s/it]

 79%|███████▊  | 990/1261 [19:59<07:20,  1.62s/it]

 79%|███████▊  | 991/1261 [20:01<07:17,  1.62s/it]

 79%|███████▊  | 992/1261 [20:03<07:15,  1.62s/it]

 79%|███████▊  | 993/1261 [20:04<07:01,  1.57s/it]

 79%|███████▉  | 994/1261 [20:05<06:29,  1.46s/it]

 79%|███████▉  | 995/1261 [20:06<06:03,  1.37s/it]

 79%|███████▉  | 996/1261 [20:08<05:47,  1.31s/it]

 79%|███████▉  | 997/1261 [20:09<05:39,  1.29s/it]

 79%|███████▉  | 998/1261 [20:10<05:41,  1.30s/it]

 79%|███████▉  | 999/1261 [20:11<05:37,  1.29s/it]

 79%|███████▉  | 1000/1261 [20:13<05:22,  1.24s/it]

 79%|███████▉  | 1001/1261 [20:14<05:06,  1.18s/it]

 79%|███████▉  | 1002/1261 [20:15<05:01,  1.17s/it]

 80%|███████▉  | 1003/1261 [20:16<05:09,  1.20s/it]

 80%|███████▉  | 1004/1261 [20:18<05:31,  1.29s/it]

 80%|███████▉  | 1005/1261 [20:19<05:25,  1.27s/it]

 80%|███████▉  | 1006/1261 [20:20<05:15,  1.24s/it]

 80%|███████▉  | 1007/1261 [20:21<05:08,  1.21s/it]

 80%|███████▉  | 1008/1261 [20:22<05:02,  1.20s/it]

 80%|████████  | 1009/1261 [20:23<04:57,  1.18s/it]

 80%|████████  | 1010/1261 [20:25<04:57,  1.19s/it]

 80%|████████  | 1011/1261 [20:26<04:55,  1.18s/it]

 80%|████████  | 1012/1261 [20:27<05:01,  1.21s/it]

 80%|████████  | 1013/1261 [20:28<04:59,  1.21s/it]

 80%|████████  | 1014/1261 [20:30<05:04,  1.23s/it]

 80%|████████  | 1015/1261 [20:31<04:59,  1.22s/it]

 81%|████████  | 1016/1261 [20:32<04:58,  1.22s/it]

 81%|████████  | 1017/1261 [20:33<04:59,  1.23s/it]

 81%|████████  | 1018/1261 [20:34<05:02,  1.25s/it]

 81%|████████  | 1019/1261 [20:36<04:57,  1.23s/it]

 81%|████████  | 1020/1261 [20:37<04:57,  1.23s/it]

 81%|████████  | 1021/1261 [20:38<04:53,  1.22s/it]

 81%|████████  | 1022/1261 [20:39<04:47,  1.20s/it]

 81%|████████  | 1023/1261 [20:41<04:52,  1.23s/it]

 81%|████████  | 1024/1261 [20:42<04:53,  1.24s/it]

 81%|████████▏ | 1025/1261 [20:43<04:56,  1.26s/it]

 81%|████████▏ | 1026/1261 [20:44<04:51,  1.24s/it]

 81%|████████▏ | 1027/1261 [20:45<04:45,  1.22s/it]

 82%|████████▏ | 1028/1261 [20:47<04:45,  1.22s/it]

 82%|████████▏ | 1029/1261 [20:48<04:46,  1.24s/it]

 82%|████████▏ | 1030/1261 [20:49<04:54,  1.27s/it]

 82%|████████▏ | 1031/1261 [20:51<04:49,  1.26s/it]

 82%|████████▏ | 1032/1261 [20:52<04:42,  1.23s/it]

 82%|████████▏ | 1033/1261 [20:53<04:42,  1.24s/it]

 82%|████████▏ | 1034/1261 [20:54<04:40,  1.24s/it]

 82%|████████▏ | 1035/1261 [20:55<04:34,  1.21s/it]

 82%|████████▏ | 1036/1261 [20:57<04:39,  1.24s/it]

 82%|████████▏ | 1037/1261 [20:58<04:43,  1.27s/it]

 82%|████████▏ | 1038/1261 [20:59<04:47,  1.29s/it]

 82%|████████▏ | 1039/1261 [21:01<04:43,  1.28s/it]

 82%|████████▏ | 1040/1261 [21:02<04:40,  1.27s/it]

 83%|████████▎ | 1041/1261 [21:03<04:38,  1.27s/it]

 83%|████████▎ | 1042/1261 [21:04<04:37,  1.27s/it]

 83%|████████▎ | 1043/1261 [21:06<04:38,  1.28s/it]

 83%|████████▎ | 1044/1261 [21:07<04:39,  1.29s/it]

 83%|████████▎ | 1045/1261 [21:08<04:29,  1.25s/it]

 83%|████████▎ | 1046/1261 [21:09<04:25,  1.24s/it]

 83%|████████▎ | 1047/1261 [21:11<04:23,  1.23s/it]

 83%|████████▎ | 1048/1261 [21:12<04:21,  1.23s/it]

 83%|████████▎ | 1049/1261 [21:13<04:15,  1.21s/it]

 83%|████████▎ | 1050/1261 [21:14<04:15,  1.21s/it]

 83%|████████▎ | 1051/1261 [21:15<04:05,  1.17s/it]

 83%|████████▎ | 1052/1261 [21:17<04:09,  1.19s/it]

 84%|████████▎ | 1053/1261 [21:18<04:03,  1.17s/it]

 84%|████████▎ | 1054/1261 [21:19<04:04,  1.18s/it]

 84%|████████▎ | 1055/1261 [21:20<03:59,  1.16s/it]

 84%|████████▎ | 1056/1261 [21:21<03:57,  1.16s/it]

 84%|████████▍ | 1057/1261 [21:22<03:52,  1.14s/it]

 84%|████████▍ | 1058/1261 [21:23<03:51,  1.14s/it]

 84%|████████▍ | 1059/1261 [21:24<03:48,  1.13s/it]

 84%|████████▍ | 1060/1261 [21:26<03:50,  1.15s/it]

 84%|████████▍ | 1061/1261 [21:27<03:51,  1.16s/it]

 84%|████████▍ | 1062/1261 [21:28<03:47,  1.14s/it]

 84%|████████▍ | 1063/1261 [21:29<03:45,  1.14s/it]

 84%|████████▍ | 1064/1261 [21:30<03:49,  1.16s/it]

 84%|████████▍ | 1065/1261 [21:31<03:46,  1.15s/it]

 85%|████████▍ | 1066/1261 [21:33<03:47,  1.17s/it]

 85%|████████▍ | 1067/1261 [21:34<03:43,  1.15s/it]

 85%|████████▍ | 1068/1261 [21:35<03:47,  1.18s/it]

 85%|████████▍ | 1069/1261 [21:36<03:39,  1.14s/it]

 85%|████████▍ | 1070/1261 [21:37<03:37,  1.14s/it]

 85%|████████▍ | 1071/1261 [21:38<03:38,  1.15s/it]

 85%|████████▌ | 1072/1261 [21:39<03:38,  1.16s/it]

 85%|████████▌ | 1073/1261 [21:41<03:34,  1.14s/it]

 85%|████████▌ | 1074/1261 [21:42<03:36,  1.16s/it]

 85%|████████▌ | 1075/1261 [21:43<03:31,  1.14s/it]

 85%|████████▌ | 1076/1261 [21:44<03:32,  1.15s/it]

 85%|████████▌ | 1077/1261 [21:45<03:30,  1.15s/it]

 85%|████████▌ | 1078/1261 [21:46<03:29,  1.15s/it]

 86%|████████▌ | 1079/1261 [21:47<03:24,  1.12s/it]

 86%|████████▌ | 1080/1261 [21:49<03:26,  1.14s/it]

 86%|████████▌ | 1081/1261 [21:50<03:25,  1.14s/it]

 86%|████████▌ | 1082/1261 [21:51<03:24,  1.14s/it]

 86%|████████▌ | 1083/1261 [21:52<03:22,  1.14s/it]

 86%|████████▌ | 1084/1261 [21:53<03:24,  1.15s/it]

 86%|████████▌ | 1085/1261 [21:54<03:22,  1.15s/it]

 86%|████████▌ | 1086/1261 [21:56<03:26,  1.18s/it]

 86%|████████▌ | 1087/1261 [21:57<03:23,  1.17s/it]

 86%|████████▋ | 1088/1261 [21:58<03:21,  1.17s/it]

 86%|████████▋ | 1089/1261 [21:59<03:20,  1.16s/it]

 86%|████████▋ | 1090/1261 [22:00<03:18,  1.16s/it]

 87%|████████▋ | 1091/1261 [22:01<03:14,  1.14s/it]

 87%|████████▋ | 1092/1261 [22:03<03:16,  1.16s/it]

 87%|████████▋ | 1093/1261 [22:04<03:13,  1.15s/it]

 87%|████████▋ | 1094/1261 [22:05<03:11,  1.15s/it]

 87%|████████▋ | 1095/1261 [22:06<03:11,  1.15s/it]

 87%|████████▋ | 1096/1261 [22:08<03:48,  1.38s/it]

 87%|████████▋ | 1097/1261 [22:09<03:44,  1.37s/it]

 87%|████████▋ | 1098/1261 [22:10<03:37,  1.33s/it]

 87%|████████▋ | 1099/1261 [22:12<03:28,  1.29s/it]

 87%|████████▋ | 1100/1261 [22:13<03:27,  1.29s/it]

 87%|████████▋ | 1101/1261 [22:14<03:17,  1.23s/it]

 87%|████████▋ | 1102/1261 [22:15<03:23,  1.28s/it]

 87%|████████▋ | 1103/1261 [22:17<03:19,  1.26s/it]

 88%|████████▊ | 1104/1261 [22:18<03:24,  1.30s/it]

 88%|████████▊ | 1105/1261 [22:19<03:20,  1.29s/it]

 88%|████████▊ | 1106/1261 [22:21<03:49,  1.48s/it]

 88%|████████▊ | 1107/1261 [22:22<03:37,  1.41s/it]

 88%|████████▊ | 1108/1261 [22:24<03:27,  1.36s/it]

 88%|████████▊ | 1109/1261 [22:25<03:26,  1.36s/it]

 88%|████████▊ | 1110/1261 [22:26<03:24,  1.35s/it]

 88%|████████▊ | 1111/1261 [22:28<03:13,  1.29s/it]

 88%|████████▊ | 1112/1261 [22:29<03:16,  1.32s/it]

 88%|████████▊ | 1113/1261 [22:30<03:06,  1.26s/it]

 88%|████████▊ | 1114/1261 [22:31<03:11,  1.30s/it]

 88%|████████▊ | 1115/1261 [22:33<03:02,  1.25s/it]

 89%|████████▊ | 1116/1261 [22:35<03:35,  1.48s/it]

 89%|████████▊ | 1117/1261 [22:36<03:29,  1.46s/it]

 89%|████████▊ | 1118/1261 [22:38<03:30,  1.47s/it]

 89%|████████▊ | 1119/1261 [22:39<03:23,  1.43s/it]

 89%|████████▉ | 1120/1261 [22:40<03:15,  1.39s/it]

 89%|████████▉ | 1121/1261 [22:42<03:13,  1.38s/it]

 89%|████████▉ | 1122/1261 [22:43<03:10,  1.37s/it]

 89%|████████▉ | 1123/1261 [22:44<03:05,  1.34s/it]

 89%|████████▉ | 1124/1261 [22:46<03:09,  1.38s/it]

 89%|████████▉ | 1125/1261 [22:47<03:02,  1.34s/it]

 89%|████████▉ | 1126/1261 [22:48<03:04,  1.37s/it]

 89%|████████▉ | 1127/1261 [22:50<03:03,  1.37s/it]

 89%|████████▉ | 1128/1261 [22:51<03:04,  1.39s/it]

 90%|████████▉ | 1129/1261 [22:52<02:55,  1.33s/it]

 90%|████████▉ | 1130/1261 [22:54<02:51,  1.31s/it]

 90%|████████▉ | 1131/1261 [22:55<02:43,  1.26s/it]

 90%|████████▉ | 1132/1261 [22:56<02:37,  1.22s/it]

 90%|████████▉ | 1133/1261 [22:57<02:33,  1.20s/it]

 90%|████████▉ | 1134/1261 [22:58<02:31,  1.19s/it]

 90%|█████████ | 1135/1261 [22:59<02:26,  1.16s/it]

 90%|█████████ | 1136/1261 [23:01<02:35,  1.24s/it]

 90%|█████████ | 1137/1261 [23:02<02:34,  1.25s/it]

 90%|█████████ | 1138/1261 [23:03<02:34,  1.26s/it]

 90%|█████████ | 1139/1261 [23:04<02:34,  1.26s/it]

 90%|█████████ | 1140/1261 [23:06<02:28,  1.22s/it]

 90%|█████████ | 1141/1261 [23:07<02:32,  1.27s/it]

 91%|█████████ | 1142/1261 [23:08<02:39,  1.34s/it]

 91%|█████████ | 1143/1261 [23:10<02:34,  1.31s/it]

 91%|█████████ | 1144/1261 [23:11<02:42,  1.39s/it]

 91%|█████████ | 1145/1261 [23:12<02:33,  1.32s/it]

 91%|█████████ | 1146/1261 [23:14<02:34,  1.34s/it]

 91%|█████████ | 1147/1261 [23:16<03:01,  1.59s/it]

 91%|█████████ | 1148/1261 [23:18<03:20,  1.78s/it]

 91%|█████████ | 1149/1261 [23:20<03:26,  1.85s/it]

 91%|█████████ | 1150/1261 [23:22<03:20,  1.81s/it]

 91%|█████████▏| 1151/1261 [23:24<03:21,  1.84s/it]

 91%|█████████▏| 1152/1261 [23:25<03:04,  1.69s/it]

 91%|█████████▏| 1153/1261 [23:27<02:58,  1.66s/it]

 92%|█████████▏| 1154/1261 [23:29<03:18,  1.85s/it]

 92%|█████████▏| 1155/1261 [23:31<03:21,  1.90s/it]

 92%|█████████▏| 1156/1261 [23:33<03:10,  1.82s/it]

 92%|█████████▏| 1157/1261 [23:34<02:54,  1.68s/it]

 92%|█████████▏| 1158/1261 [23:36<02:57,  1.72s/it]

 92%|█████████▏| 1159/1261 [23:37<02:43,  1.61s/it]

 92%|█████████▏| 1160/1261 [23:39<02:39,  1.58s/it]

 92%|█████████▏| 1161/1261 [23:41<02:56,  1.77s/it]

 92%|█████████▏| 1162/1261 [23:42<02:40,  1.62s/it]

 92%|█████████▏| 1163/1261 [23:44<02:43,  1.67s/it]

 92%|█████████▏| 1164/1261 [23:45<02:36,  1.61s/it]

 92%|█████████▏| 1165/1261 [23:47<02:22,  1.49s/it]

 92%|█████████▏| 1166/1261 [23:48<02:23,  1.51s/it]

 93%|█████████▎| 1167/1261 [23:49<02:11,  1.40s/it]

 93%|█████████▎| 1168/1261 [23:51<02:03,  1.33s/it]

 93%|█████████▎| 1169/1261 [23:52<01:56,  1.27s/it]

 93%|█████████▎| 1170/1261 [23:53<01:52,  1.24s/it]

 93%|█████████▎| 1171/1261 [23:54<01:47,  1.19s/it]

 93%|█████████▎| 1172/1261 [23:55<01:44,  1.18s/it]

 93%|█████████▎| 1173/1261 [23:56<01:41,  1.16s/it]

 93%|█████████▎| 1174/1261 [23:57<01:42,  1.18s/it]

 93%|█████████▎| 1175/1261 [23:59<01:38,  1.15s/it]

 93%|█████████▎| 1176/1261 [24:00<01:36,  1.14s/it]

 93%|█████████▎| 1177/1261 [24:01<01:33,  1.11s/it]

 93%|█████████▎| 1178/1261 [24:02<01:32,  1.11s/it]

 93%|█████████▎| 1179/1261 [24:03<01:34,  1.16s/it]

 94%|█████████▎| 1180/1261 [24:04<01:33,  1.15s/it]

 94%|█████████▎| 1181/1261 [24:05<01:30,  1.13s/it]

 94%|█████████▎| 1182/1261 [24:06<01:28,  1.12s/it]

 94%|█████████▍| 1183/1261 [24:07<01:25,  1.10s/it]

 94%|█████████▍| 1184/1261 [24:09<01:24,  1.10s/it]

 94%|█████████▍| 1185/1261 [24:10<01:22,  1.08s/it]

 94%|█████████▍| 1186/1261 [24:11<01:23,  1.11s/it]

 94%|█████████▍| 1187/1261 [24:12<01:21,  1.10s/it]

 94%|█████████▍| 1188/1261 [24:13<01:20,  1.10s/it]

 94%|█████████▍| 1189/1261 [24:14<01:18,  1.09s/it]

 94%|█████████▍| 1190/1261 [24:15<01:18,  1.10s/it]

 94%|█████████▍| 1191/1261 [24:16<01:16,  1.09s/it]

 95%|█████████▍| 1192/1261 [24:17<01:15,  1.09s/it]

 95%|█████████▍| 1193/1261 [24:18<01:13,  1.08s/it]

 95%|█████████▍| 1194/1261 [24:19<01:13,  1.09s/it]

 95%|█████████▍| 1195/1261 [24:20<01:11,  1.08s/it]

 95%|█████████▍| 1196/1261 [24:22<01:10,  1.09s/it]

 95%|█████████▍| 1197/1261 [24:23<01:10,  1.10s/it]

 95%|█████████▌| 1198/1261 [24:24<01:09,  1.10s/it]

 95%|█████████▌| 1199/1261 [24:25<01:07,  1.09s/it]

 95%|█████████▌| 1200/1261 [24:26<01:06,  1.09s/it]

 95%|█████████▌| 1201/1261 [24:27<01:04,  1.07s/it]

 95%|█████████▌| 1202/1261 [24:28<01:03,  1.08s/it]

 95%|█████████▌| 1203/1261 [24:29<01:03,  1.09s/it]

 95%|█████████▌| 1204/1261 [24:30<01:02,  1.10s/it]

 96%|█████████▌| 1205/1261 [24:31<01:01,  1.10s/it]

 96%|█████████▌| 1206/1261 [24:33<01:00,  1.10s/it]

 96%|█████████▌| 1207/1261 [24:34<00:58,  1.08s/it]

 96%|█████████▌| 1208/1261 [24:35<00:59,  1.12s/it]

 96%|█████████▌| 1209/1261 [24:36<00:56,  1.09s/it]

 96%|█████████▌| 1210/1261 [24:37<00:55,  1.10s/it]

 96%|█████████▌| 1211/1261 [24:38<00:54,  1.10s/it]

 96%|█████████▌| 1212/1261 [24:39<00:54,  1.11s/it]

 96%|█████████▌| 1213/1261 [24:40<00:53,  1.11s/it]

 96%|█████████▋| 1214/1261 [24:41<00:52,  1.13s/it]

 96%|█████████▋| 1215/1261 [24:43<00:51,  1.11s/it]

 96%|█████████▋| 1216/1261 [24:44<00:49,  1.10s/it]

 97%|█████████▋| 1217/1261 [24:45<00:48,  1.11s/it]

 97%|█████████▋| 1218/1261 [24:46<00:48,  1.12s/it]

 97%|█████████▋| 1219/1261 [24:47<00:45,  1.09s/it]

 97%|█████████▋| 1220/1261 [24:48<00:45,  1.10s/it]

 97%|█████████▋| 1221/1261 [24:49<00:44,  1.10s/it]

 97%|█████████▋| 1222/1261 [24:50<00:42,  1.09s/it]

 97%|█████████▋| 1223/1261 [24:51<00:41,  1.09s/it]

 97%|█████████▋| 1224/1261 [24:52<00:40,  1.10s/it]

 97%|█████████▋| 1225/1261 [24:53<00:39,  1.09s/it]

 97%|█████████▋| 1226/1261 [24:55<00:39,  1.12s/it]

 97%|█████████▋| 1227/1261 [24:56<00:37,  1.11s/it]

 97%|█████████▋| 1228/1261 [24:57<00:36,  1.11s/it]

 97%|█████████▋| 1229/1261 [24:58<00:35,  1.11s/it]

 98%|█████████▊| 1230/1261 [24:59<00:34,  1.12s/it]

 98%|█████████▊| 1231/1261 [25:00<00:32,  1.10s/it]

 98%|█████████▊| 1232/1261 [25:01<00:32,  1.11s/it]

 98%|█████████▊| 1233/1261 [25:02<00:31,  1.12s/it]

 98%|█████████▊| 1234/1261 [25:04<00:30,  1.12s/it]

 98%|█████████▊| 1235/1261 [25:05<00:33,  1.27s/it]

 98%|█████████▊| 1236/1261 [25:07<00:33,  1.34s/it]

 98%|█████████▊| 1237/1261 [25:08<00:30,  1.29s/it]

 98%|█████████▊| 1238/1261 [25:09<00:29,  1.26s/it]

 98%|█████████▊| 1239/1261 [25:10<00:27,  1.25s/it]

 98%|█████████▊| 1240/1261 [25:12<00:27,  1.33s/it]

 98%|█████████▊| 1241/1261 [25:13<00:25,  1.27s/it]

 98%|█████████▊| 1242/1261 [25:14<00:23,  1.24s/it]

 99%|█████████▊| 1243/1261 [25:15<00:22,  1.22s/it]

 99%|█████████▊| 1244/1261 [25:16<00:20,  1.20s/it]

 99%|█████████▊| 1245/1261 [25:18<00:19,  1.20s/it]

 99%|█████████▉| 1246/1261 [25:19<00:17,  1.18s/it]

 99%|█████████▉| 1247/1261 [25:20<00:16,  1.15s/it]

 99%|█████████▉| 1248/1261 [25:21<00:15,  1.16s/it]

 99%|█████████▉| 1249/1261 [25:22<00:13,  1.16s/it]

 99%|█████████▉| 1250/1261 [25:23<00:12,  1.14s/it]

 99%|█████████▉| 1251/1261 [25:24<00:11,  1.15s/it]

 99%|█████████▉| 1252/1261 [25:26<00:10,  1.16s/it]

 99%|█████████▉| 1253/1261 [25:27<00:09,  1.13s/it]

 99%|█████████▉| 1254/1261 [25:28<00:08,  1.15s/it]

100%|█████████▉| 1255/1261 [25:29<00:06,  1.15s/it]

100%|█████████▉| 1256/1261 [25:30<00:05,  1.17s/it]

100%|█████████▉| 1257/1261 [25:31<00:04,  1.16s/it]

100%|█████████▉| 1258/1261 [25:33<00:03,  1.17s/it]

100%|█████████▉| 1259/1261 [25:34<00:02,  1.16s/it]

100%|█████████▉| 1260/1261 [25:35<00:01,  1.16s/it]

[MoviePy] Done.
[MoviePy] >>>> Video ready: data/output_images/comp_processed_project_video.mp4 

Out[31]: